0605 ljc 目标模块调试完成,新增pageResult构造方法,完善分页信息返回,报告模块开发,上传下载接口开发,新增sftp工具方法,健壮BeanIdReq适用范围,新增BeanIdPageReq,替换所有BeanUtils方法

This commit is contained in:
HopeLi 2025-06-05 15:33:52 +08:00
parent 3eff2984eb
commit 447543962f
29 changed files with 912 additions and 127 deletions

View File

@ -17,6 +17,12 @@ public final class PageResult<T> implements Serializable {
@Schema(description = "总量", requiredMode = Schema.RequiredMode.REQUIRED)
private Long total;
@Schema(description = "分页查询页数", requiredMode = Schema.RequiredMode.REQUIRED)
private Long pageNun;
@Schema(description = "每页条数", requiredMode = Schema.RequiredMode.REQUIRED)
private Long pageSize;
public PageResult() {
}
@ -25,6 +31,13 @@ public final class PageResult<T> implements Serializable {
this.total = total;
}
public PageResult(List<T> list, Long total , Long pageNun, Long pageSize) {
this.list = list;
this.total = total;
this.pageNun = pageNun;
this.pageSize = pageSize;
}
public PageResult(Long total) {
this.list = new ArrayList<>();
this.total = total;

View File

@ -0,0 +1,65 @@
package cd.casic.ci.api;
import cd.casic.ci.process.dal.req.report.ReportDeleteReq;
import cd.casic.ci.process.dal.resp.report.ReportResp;
import cd.casic.ci.process.process.dataObject.base.BaseIdPageReq;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.service.report.ReportService;
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 java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
* @ClassName ReportController
* @Author hopeli
* @Date 2025/5/10 10:28
* @Version 1.0
*/
@RestController
@RequestMapping("/report")
public class ReportController {
@Resource
private ReportService reportService;
@PermitAll
@PostMapping(path="/findReportList")
public CommonResult<PageResult<ReportResp>> findReportList(@RequestBody @Valid BaseIdPageReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
PageResult<ReportResp> respPage = reportService.findReportList(req);
return CommonResult.success(respPage);
}
@PostMapping(path="/deleteReport")
public CommonResult<ReportResp> deleteReport(@RequestBody @Valid ReportDeleteReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
ReportResp reportResp = reportService.deleteReport(req);
return CommonResult.success(reportResp);
}
@PostMapping(path="/downLoadReport")
public CommonResult<String> downLoadReport(@RequestBody @NotNull @Valid BaseIdReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
String xmTraceId = reportService.downLoadReport(req);
return CommonResult.success(xmTraceId);
}
}

View File

@ -3,13 +3,14 @@ package cd.casic.ci.api;
import cd.casic.ci.process.dal.req.target.*;
import cd.casic.ci.process.dal.resp.target.TargetManagerResp;
import cd.casic.ci.process.dal.resp.target.TargetVersionResp;
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 cn.hutool.core.io.resource.InputStreamResource;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
@ -17,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.List;
/**
@ -55,6 +57,15 @@ public class TargetController {
}
@PostMapping(value = "/updateVersion")
@PermitAll
public CommonResult<Void> updateVersion(@RequestBody @Valid TargetVersionUpdateReq req){
targetManagerService.updateVersion(req);
return CommonResult.success();
}
@PostMapping(value = "/updateTarget")
@PermitAll
public CommonResult<Void> updateTarget(@RequestBody @Valid TargetManagerUpdateReq req) {
@ -104,9 +115,9 @@ public class TargetController {
@PostMapping(path="/selectListByManagerId")
@PermitAll
public CommonResult<List<TargetVersion>> selectListByManagerId(@RequestBody @Valid BaseIdReq query){
public CommonResult<List<TargetVersionResp>> selectListByManagerId(@RequestBody @Valid BaseIdReq query){
List<TargetVersion> respList = targetVersionService.selectListByManagerId(query.getId());
List<TargetVersionResp> respList = targetVersionService.selectListByManagerId(query.getId());
return CommonResult.success(respList);
}
@ -121,4 +132,13 @@ public class TargetController {
return CommonResult.success(filePath);
}
@PostMapping(path="/fileDownload")
public CommonResult<InputStreamResource> fileDownload(@RequestBody @Valid TargetDownloadReq req) throws SftpUploadUtil.SftpUploadException {
InputStream inputStream = targetManagerService.fileDownload(req);
return CommonResult.success(new InputStreamResource(inputStream));
}
}

View File

@ -0,0 +1,56 @@
package cd.casic.ci.process.dal.req.report;
import lombok.Data;
import java.util.List;
/**
* @ClassName PipelineReq
* @Author hopeli
* @Date 2025/5/10 10:53
* @Version 1.0
*/
@Data
public class ReportDeleteReq {
//开始时间
private String startDate;
//结束时间
private String endDate;
//报告名
private String name;
//项目id列表
private List<Integer> projectIdList;
//报告ID
private Integer reportId;
//报告状态 0-生成中 1-已生成 2-生成失败
private Integer status;
//报告类型 1-word 2-pdf 3-html 4-json 5-excel 6-rdf 7-tag:value 8-xml 9-yaml 10 cbor
private Integer type;
//生成用户
private String use;
//来源编号
// -1-代码溯源分析
// 0-项目管理
// 1-应用包审查分析
// 2-SBOM风险扫描
// 3-IDE开发管理
// 4-代码仓库管理
// 5-CI/CD流水线
// 6-二进制成分分析
// 7-镜像安全扫描
// 8-私服库安全扫描
// 12-组件风险管理
// 13-漏洞风险管理
// 14-许可证风险管理
// 15-知识库查询
// 16-运行时监控
private Integer sourceCode;
}

View File

@ -0,0 +1,31 @@
package cd.casic.ci.process.dal.req.target;
import lombok.Data;
/**
* @ClassName PipelineQueryReq
* @Author hopeli
* @Date 2025/5/10 9:54
* @Version 1.0
*/
@Data
public class TargetDownloadReq {
//远程服务器IP或主机名
private String remoteHost = "175.6.27.252";
//远程服务器端口 (通常是 22) null <= 0 时使用默认端口 22
private Integer remotePort = 22;
//远程服务器用户名
private String username = "roots";
//远程服务器密码 (如果使用密码认证)
private String password = "hnidc0327cn!@#xhh";
//SSH Key 文件路径 (如果使用密钥认证password 参数可以为 null)
private String sshKeyPath;
//文件地址包含文件名
private String remoteFilePath;
}

View File

@ -26,16 +26,16 @@ public class TargetManagerCreateReq {
*/
private String targetType;
/**
* 版本号
*/
private String version;
/**
* 描述
*/
private String targetDesc;
/**
* 版本号
*/
private String version;
/**
* 文件大小单位字节
*/

View File

@ -31,33 +31,8 @@ public class TargetManagerUpdateReq {
*/
private String targetType;
/**
* 版本号
*/
private String version;
/**
* 描述
*/
private String targetDesc;
/**
* 文件大小单位字节
*/
private Double fileSize;
/**
* 文件名称
*/
private String fileName;
/**
* 文件类型例如 ziptar.gz
*/
private String fileType;
/**
* 文件地址路径
*/
private String filePath;
}

View File

@ -17,21 +17,11 @@ public class TargetVersionCreateReq {
*/
private String targetId;
/**
* 目标类型
*/
private String targetType;
/**
* 版本号
*/
private String version;
/**
* 描述
*/
private String targetDesc;
/**
* 文件大小单位字节
*/

View File

@ -0,0 +1,45 @@
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 TargetVersionUpdateReq {
private String id;
/**
* 目标ID
*/
private String targetId;
/**
* 版本号
*/
private String version;
/**
* 文件大小单位字节
*/
private Double fileSize;
/**
* 文件名称
*/
private String fileName;
/**
* 文件类型例如 ziptar.gz
*/
private String fileType;
/**
* 文件地址路径
*/
private String filePath;
}

View File

@ -0,0 +1,85 @@
package cd.casic.ci.process.dal.resp.report;
import lombok.Data;
import java.util.List;
/**
* @ClassName ReportResp
* @Author hopeli
* @Date 2025/5/10 10:53
* @Version 1.0
*/
@Data
public class ReportResp {
//报告编号
private Integer id;
//报告生成时间
private String createDate;
//生成人
private String creator;
//报告维度 0-仓库 1-项目 2-应用 5-组件 6-漏洞 7-许可证
private Integer dimension;
//报告md5
private String md5;
//报告名
private String name;
//所属项目
private String projectName;
//报告编号
private String serialNumber;
//报告来源编号
// -1-代码溯源分析
// 0-项目管理
// 1-应用包审查分析
// 2-SBOM风险扫描
// 3-IDE开发管理
// 4-代码仓库管理
// 5-CI/CD流水线
// 6-二进制成分分析
// 7-镜像安全扫描
// 8-私服库安全扫描
// 12-组件风险管理
// 13-漏洞风险管理
// 14-许可证风险管理
// 15-知识库查询
// 16-运行时监控
private Integer source;
//报告来源名称
private String sourceName;
//报告状态 0-生成中 1-已生成 2-生成失败
private Integer status;
//报告类型
// 1-word
// 2-pdf
// 3-html
// 4-json
// 5-excel
// 6-rdf
// 7-tag/value(.spdx)
// 8-xml
// 9-yaml
// 10-cbor
// 11-tag/value(.dsdx)
private List<Integer> type;
//xm-trace-id
private String xmTraceId;
private Integer fail;
private Integer success;
}

View File

@ -30,6 +30,12 @@ public class TargetManagerResp{
*/
private String projectId;
/**
* 描述
*/
private String targetDesc;
/**
* 创建时间
*/

View File

@ -0,0 +1,18 @@
package cd.casic.ci.process.dal.resp.target;
import lombok.Data;
import java.io.InputStream;
/**
* @author HopeLi
* @version v1.0
* @ClassName TargetManager
* @Date: 2025/5/17 10:23
* @Description:
*/
@Data
public class TargetUploadResp {
private String filePath;
private InputStream inputStream;
}

View File

@ -2,6 +2,8 @@ package cd.casic.ci.process.dal.resp.target;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author HopeLi
* @version v1.0
@ -64,4 +66,19 @@ public class TargetVersionResp {
* 文件地址路径
*/
private String filePath;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 最后更新时间
*/
private LocalDateTime updateTime;
private String creator;
private String creatorName;
private String updater;
private String updaterName;
}

View File

@ -1,8 +1,11 @@
package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq;
import cd.casic.ci.process.dal.req.target.TargetManagerUpdateReq;
import cd.casic.ci.process.dal.resp.target.TargetManagerResp;
import cd.casic.ci.process.process.dataObject.target.TargetManager;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.util.List;
@ -21,4 +24,7 @@ public interface TargetConverter {
TargetManagerResp toResp(TargetManager targetManager);
List<TargetManagerResp> toRespList(List<TargetManager> targetManagers);
TargetManager createReqToBean(TargetManagerCreateReq req);
void updateReqToBean(TargetManagerUpdateReq req,@MappingTarget TargetManager targetManager);
}

View File

@ -0,0 +1,34 @@
package cd.casic.ci.process.process.converter;
import cd.casic.ci.process.dal.req.target.TargetManagerCreateReq;
import cd.casic.ci.process.dal.req.target.TargetVersionCreateReq;
import cd.casic.ci.process.dal.req.target.TargetVersionUpdateReq;
import cd.casic.ci.process.dal.resp.target.TargetVersionResp;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* @author HopeLi
* @version v1.0
* @ClassName PipelineConverter
* @Date: 2025/5/13 14:39
* @Description:
*/
@Mapper(componentModel = "spring",nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface TargetVersionConverter {
TargetVersionConverter INSTANCE = Mappers.getMapper(TargetVersionConverter.class);
TargetVersionResp toResp(TargetVersion targetVersion);
List<TargetVersionResp> toRespList(List<TargetVersion> targetVersions);
void updateReqCopyToTargetVersion(TargetVersionUpdateReq req,@MappingTarget TargetVersion targetVersion);
TargetVersion targetCreateReqToTargetVersionBean(TargetManagerCreateReq req);
TargetVersion versionCreateReqToTargetVersionBean(TargetVersionCreateReq req);
}

View File

@ -0,0 +1,22 @@
package cd.casic.ci.process.process.dataObject.base;
import cd.casic.framework.commons.pojo.PageParam;
import lombok.Data;
import java.util.List;
/**
* @author HopeLi
* @version v1.0
* @ClassName BaseIdPageReq
* @Date: 2025/5/17 16:40
* @Description:
*/
@Data
public class BaseIdPageReq extends PageParam {
private String id;
private List<String> idList;
private String pid;
private String childId;
private String projectId;
}

View File

@ -15,4 +15,8 @@ import java.util.List;
public class BaseIdReq {
private String id;
private List<String> idList;
private String pid;
private String childId;
private String projectId;
private List<Integer> reportIds;
}

View File

@ -31,4 +31,9 @@ public class TargetManager extends PipBaseElement {
* 组织ID
*/
private String projectId;
/**
* 描述
*/
private String targetDesc;
}

View File

@ -27,11 +27,6 @@ public class TargetVersion extends PipBaseElement {
*/
private String version;
/**
* 描述
*/
private String targetDesc;
/**
* 文件大小单位字节
*/

View File

@ -28,7 +28,6 @@ import cd.casic.ci.process.process.service.template.impl.TemplateManagerServiceI
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.commons.util.util.WebFrameworkUtils;
import cd.casic.framework.security.dal.user.AdminUserDO;
import cd.casic.framework.tenant.core.service.AdminUserServiceImpl;
@ -45,11 +44,7 @@ import org.springframework.util.ObjectUtils;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author HopeLi
@ -288,7 +283,6 @@ public class PipelineServiceImpl extends ServiceImpl<PipelineDao, PipPipeline> i
@Override
public PageResult<PipelineFindResp> findPipelinePage(PipelineQueryReq query) {
Page<PipelineFindResp> respPage = new Page<>();
QueryWrapper<PipPipeline> wrapper = new QueryWrapper<>();
if (!ObjectUtils.isEmpty(query.getId())){
@ -321,11 +315,7 @@ public class PipelineServiceImpl extends ServiceImpl<PipelineDao, PipPipeline> i
respList.forEach(this::setStageAndTask);
respList.forEach(this::setUserName);
respPage.setRecords(respList);
respPage.setTotal(pipPipelinePage.getTotal());
respPage.setCurrent(pipPipelinePage.getCurrent());
respPage.setSize(pipPipelinePage.getSize());
PageResult<PipelineFindResp> pageResult = new PageResult<>(respList,pipPipelinePage.getTotal());
PageResult<PipelineFindResp> pageResult = new PageResult<>(respList,pipPipelinePage.getTotal(),pipPipelinePage.getCurrent(),pipPipelinePage.getSize());
return pageResult;
}

View File

@ -0,0 +1,27 @@
package cd.casic.ci.process.process.service.report;
import cd.casic.ci.process.dal.req.report.ReportDeleteReq;
import cd.casic.ci.process.dal.resp.report.ReportResp;
import cd.casic.ci.process.process.dataObject.base.BaseIdPageReq;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.framework.commons.pojo.PageResult;
import jakarta.validation.Valid;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
* @author HopeLi
* @version v1.0
* @ClassName TargetVersionService
* @Date: 2025/5/17 10:20
* @Description:
*/
public interface ReportService{
PageResult<ReportResp> findReportList(@Valid BaseIdPageReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
ReportResp deleteReport(@Valid ReportDeleteReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
String downLoadReport(@Valid BaseIdReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException;
}

View File

@ -0,0 +1,200 @@
package cd.casic.ci.process.process.service.report.impl;
import cd.casic.ci.process.dal.req.report.ReportDeleteReq;
import cd.casic.ci.process.dal.resp.report.ReportResp;
import cd.casic.ci.process.engine.context.ConstantContextHolder;
import cd.casic.ci.process.process.dataObject.base.BaseIdPageReq;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
import cd.casic.ci.process.process.service.report.ReportService;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import cd.casic.framework.commons.pojo.PageResult;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import static cd.casic.ci.process.engine.worker.base.HttpWorker.getRestTemplateWithoutSANCheck;
/**
* @author HopeLi
* @version v1.0
* @ClassName TargetVersionServiceImpl
* @Date: 2025/5/17 15:20
* @Description:
*/
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
@Override
public PageResult<ReportResp> findReportList(BaseIdPageReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RestTemplate restTemplate = getRestTemplateWithoutSANCheck();
String reportFindUrl = ConstantContextHolder.getScaIp() + "openapi/v1/asset/report/list";
MultiValueMap<String, Object> body = buildFindRequestBody(req);
HttpHeaders headers = createHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
log.info("报告分页查询接口:" + reportFindUrl);
JSONObject response = restTemplate.postForObject(reportFindUrl, requestEntity, JSONObject.class);
String message = response.getString("message");
if (message.equals("success")) {
List<ReportResp> respList = new ArrayList<>();
log.info("===============报告分页查询接口成功=================");
JSONObject data = response.getJSONObject("data");
setReportFindResp(data,response.getString("xmTraceId"),respList);
PageResult<ReportResp> pageResult = new PageResult<>(respList,data.getLong("total"),data.getLong("pageNum"),data.getLong("pageSize"));
return pageResult;
} else {
log.error("===============报告分页查询接口失败=================");
return new PageResult<>();
}
}
@Override
public ReportResp deleteReport(ReportDeleteReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RestTemplate restTemplate = getRestTemplateWithoutSANCheck();
String reportDeleteUrl = ConstantContextHolder.getScaIp() + "openapi/v1/asset/report/delet";
MultiValueMap<String, Object> body = buildDeleteRequestBody(req);
HttpHeaders headers = createHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
log.info("报告删除接口:" + reportDeleteUrl);
JSONObject response = restTemplate.postForObject(reportDeleteUrl, requestEntity, JSONObject.class);
String message = response.getString("message");
if (message.equals("success")) {
ReportResp reportResp = new ReportResp();
log.info("===============报告删除接口成功=================");
JSONObject data = response.getJSONObject("data");
setReportDeleteResp(data,response.getString("xmTraceId"),reportResp);
return reportResp;
} else {
log.error("===============报告删除接口失败=================");
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"删除报告失败");
}
}
@Override
public String downLoadReport(BaseIdReq req) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RestTemplate restTemplate = getRestTemplateWithoutSANCheck();
String reportDeleteUrl = ConstantContextHolder.getScaIp() + "openapi/v1/asset/report/downLoadReport/batch";
MultiValueMap<String, Object> body = buildDownloadRequestBody(req);
HttpHeaders headers = createHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
log.info("报告下载接口:" + reportDeleteUrl);
JSONObject response = restTemplate.postForObject(reportDeleteUrl, requestEntity, JSONObject.class);
String message = response.getString("message");
if (message.equals("success")) {
ReportResp reportResp = new ReportResp();
log.info("===============报告下载接口成功=================");
return response.getString("xmTraceId");
} else {
log.error("===============报告下载接口失败=================");
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"删除报告失败");
}
}
private HttpHeaders createHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.add("OpenApiUserToken", ConstantContextHolder.getScaToken());
return headers;
}
private MultiValueMap<String, Object> buildFindRequestBody(BaseIdPageReq req) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("projectId", req.getProjectId());
body.add("pageNum", req.getPageNo());
body.add("pageSize", req.getPageSize());
return body;
}
private MultiValueMap<String, Object> buildDeleteRequestBody(ReportDeleteReq req) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("endDate", req.getEndDate());
body.add("name", req.getName());
body.add("projectIdList", req.getProjectIdList());
body.add("reportId", req.getReportId());
body.add("sourceCode", req.getSourceCode());
body.add("startDate", req.getStartDate());
body.add("status", req.getStatus());
body.add("type", req.getType());
body.add("use", req.getUse());
return body;
}
private MultiValueMap<String, Object> buildDownloadRequestBody(BaseIdReq req) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("reportIds", req.getReportIds());
return body;
}
private void setReportFindResp(JSONObject data, String xmTraceId, List<ReportResp> respList) {
data.getJSONArray("records").forEach(item -> {
JSONObject report = (JSONObject) item;
ReportResp reportResp = new ReportResp();
reportResp.setId(report.getInteger("id"));
reportResp.setCreateDate(report.getString("createDate"));
reportResp.setCreator(report.getString("creator"));
reportResp.setDimension(report.getInteger("dimension"));
reportResp.setMd5(report.getString("md5"));
reportResp.setName(report.getString("name"));
reportResp.setProjectName(report.getString("projectName"));
reportResp.setSerialNumber(report.getString("serialNumber"));
reportResp.setSource(report.getInteger("source"));
reportResp.setSourceName(report.getString("sourceName"));
reportResp.setStatus(report.getInteger("status"));
reportResp.setXmTraceId(xmTraceId);
List<Integer> typeList = new ArrayList<>();
report.getJSONArray("type").forEach(o->{
typeList.add((Integer) o);
});
reportResp.setType(typeList);
respList.add(reportResp);
});
}
private void setReportDeleteResp(JSONObject data, String xmTraceId, ReportResp reportResp) {
reportResp.setFail(data.getInteger("fail"));
reportResp.setSuccess(data.getInteger("success"));
reportResp.setXmTraceId(xmTraceId);
}
}

View File

@ -232,7 +232,6 @@ public class ResourceManagerServiceImpl extends ServiceImpl<PipResourceManagerDa
@Override
public PageResult<ResourceFindResp> findResourcePage(ResourceQueryReq query) {
Page<ResourceFindResp> respPage = new Page<>();
QueryWrapper<PipResourceManager> wrapper = new QueryWrapper<>();
if (!ObjectUtils.isEmpty(query.getId())){
@ -271,11 +270,7 @@ public class ResourceManagerServiceImpl extends ServiceImpl<PipResourceManagerDa
respList.forEach(this::setResource);
respList.forEach(this::setUserName);
respPage.setRecords(respList);
respPage.setTotal(pipResourceTempPage.getTotal());
respPage.setCurrent(pipResourceTempPage.getCurrent());
respPage.setSize(pipResourceTempPage.getSize());
PageResult<ResourceFindResp> pageResult = new PageResult<>(respList,pipResourceTempPage.getTotal());
PageResult<ResourceFindResp> pageResult = new PageResult<>(respList,pipResourceTempPage.getTotal(),pipResourceTempPage.getCurrent(),pipResourceTempPage.getSize());
return pageResult;
}

View File

@ -10,6 +10,7 @@ import cd.casic.framework.commons.pojo.PageResult;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.validation.Valid;
import java.io.InputStream;
import java.util.List;
/**
@ -35,4 +36,8 @@ public interface TargetManagerService extends IService<TargetManager> {
void createVersion(@Valid TargetVersionCreateReq req);
void deleteVersion(@Valid BaseIdReq req);
void updateVersion(@Valid TargetVersionUpdateReq req);
InputStream fileDownload(@Valid TargetDownloadReq req) throws SftpUploadUtil.SftpUploadException;
}

View File

@ -1,5 +1,6 @@
package cd.casic.ci.process.process.service.target;
import cd.casic.ci.process.dal.resp.target.TargetVersionResp;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import com.baomidou.mybatisplus.extension.service.IService;
@ -13,5 +14,5 @@ import java.util.List;
* @Description:
*/
public interface TargetVersionService extends IService<TargetVersion> {
List<TargetVersion> selectListByManagerId(String targetId);
List<TargetVersionResp> selectListByManagerId(String targetId);
}

View File

@ -3,7 +3,9 @@ package cd.casic.ci.process.process.service.target.impl;
import cd.casic.ci.process.dal.req.target.*;
import cd.casic.ci.process.dal.resp.target.TargetManagerResp;
import cd.casic.ci.process.dal.resp.target.TargetVersionResp;
import cd.casic.ci.process.process.converter.TargetConverter;
import cd.casic.ci.process.process.converter.TargetVersionConverter;
import cd.casic.ci.process.process.dal.pipeline.TargetManagerDao;
import cd.casic.ci.process.process.dal.pipeline.TargetVersionDao;
import cd.casic.ci.process.process.dataObject.base.BaseIdReq;
@ -14,10 +16,8 @@ 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 cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -26,9 +26,9 @@ import lombok.extern.slf4j.Slf4j;
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.ObjectUtils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@ -60,13 +60,19 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
@Override
@Transactional(rollbackFor = Exception.class)
public void createTarget(TargetManagerCreateReq req) {
TargetManager targetManager = new TargetManager();
BeanUtils.copyProperties(req, targetManager);
TargetManager targetManager = TargetConverter.INSTANCE.createReqToBean(req);
//根据目标名称做全局唯新校验
QueryWrapper<TargetManager> wrapper = new QueryWrapper<>();
wrapper.eq("target_name",targetManager.getTargetName());
if (!ObjectUtils.isEmpty(targetManagerDao.selectList(wrapper))){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标名称已存在");
}
this.save(targetManager);
//保存第一个版本
TargetVersion targetVersion = new TargetVersion();
BeanUtil.copyProperties(req,targetVersion);
TargetVersion targetVersion = TargetVersionConverter.INSTANCE.targetCreateReqToTargetVersionBean(req);
targetVersion.setTargetId(targetManager.getId());
targetVersionService.save(targetVersion);
}
@ -83,30 +89,9 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"数据错误,请联系管理员");
}
BeanUtils.copyProperties(req,targetManager);
TargetConverter.INSTANCE.updateReqToBean(req,targetManager);
targetManagerDao.updateById(targetManager);
//根据版本号和targetId查询是修改当前版本的信息还是新增新版本
QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>();
wrapper.eq("target_id",targetManager.getId());
wrapper.eq("version",req.getVersion());
List<TargetVersion> versionList = targetVersionDao.selectList(wrapper);
if (CollectionUtils.isEmpty(versionList)){
//新增一条版本信息
TargetVersion targetVersion = new TargetVersion();
BeanUtil.copyProperties(req,targetVersion);
targetVersion.setId(null);
targetVersion.setTargetId(targetManager.getId());
targetVersionService.save(targetVersion);
}else {
TargetVersion targetVersion = versionList.get(0);
String versionId = targetVersion.getId();
BeanUtils.copyProperties(req,targetVersion);
targetVersion.setId(versionId);
targetVersionService.updateById(targetVersion);
}
}
@ -124,14 +109,13 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
targetManagerDao.deleteById(targetManager.getId());
//删除对应的version版本
List<TargetVersion> versionList = targetVersionService.selectListByManagerId(targetManager.getId());
List<String> versionIdList = versionList.stream().map(TargetVersion::getId).toList();
List<TargetVersionResp> versionList = targetVersionService.selectListByManagerId(targetManager.getId());
List<String> versionIdList = versionList.stream().map(TargetVersionResp::getId).toList();
targetVersionDao.deleteByIds(versionIdList);
}
@Override
public PageResult<TargetManagerResp> findTargetPage(TargetQueryReq query) {
Page<TargetManagerResp> respPage = new Page<>();
QueryWrapper<TargetManager> wrapper = new QueryWrapper<>();
if (!ObjectUtils.isEmpty(query.getId())){
@ -159,11 +143,7 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
List<TargetManagerResp> respList = TargetConverter.INSTANCE.toRespList(targetManagerPage.getRecords());
respList.forEach(this::setUserName);
respPage.setRecords(respList);
respPage.setTotal(targetManagerPage.getTotal());
respPage.setCurrent(targetManagerPage.getCurrent());
respPage.setSize(targetManagerPage.getSize());
PageResult<TargetManagerResp> pageResult = new PageResult<>(respList,targetManagerPage.getTotal());
PageResult<TargetManagerResp> pageResult = new PageResult<>(respList,targetManagerPage.getTotal(),targetManagerPage.getCurrent(),targetManagerPage.getSize());
return pageResult;
}
@ -216,7 +196,7 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
public String fileUpload(TargetUploadReq req) throws SftpUploadUtil.SftpUploadException {
String filePath = req.getRemoteDir() + UUID.randomUUID();
SftpUploadUtil.uploadFileSftp(
String path = SftpUploadUtil.uploadFileSftp(
req.getRemoteHost(),
req.getRemotePort(),
req.getUsername(),
@ -226,18 +206,63 @@ public class TargetManagerServiceImpl extends ServiceImpl<TargetManagerDao, Targ
filePath,
req.getRemoteFileName()
);
return filePath;
return path;
}
@Override
public void createVersion(TargetVersionCreateReq req) {
TargetVersion targetVersion = new TargetVersion();
BeanUtil.copyProperties(req,targetVersion);
TargetVersion targetVersion = TargetVersionConverter.INSTANCE.versionCreateReqToTargetVersionBean(req);
//根据版本做局部唯新校验
QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>();
wrapper.eq("version",targetVersion.getVersion());
wrapper.eq("target_id",targetVersion.getTargetId());
if (!ObjectUtils.isEmpty(targetVersionDao.selectList(wrapper))){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"版本已存在");
}
targetVersionService.save(targetVersion);
}
@Override
public void deleteVersion(BaseIdReq req) {
targetManagerDao.deleteById(req.getId());
targetVersionDao.deleteById(req.getId());
}
@Override
public void updateVersion(TargetVersionUpdateReq req){
if (ObjectUtils.isEmpty(req.getId())){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标id不能为空");
}
TargetVersion targetVersion = targetVersionDao.selectById(req.getId());
if (ObjectUtils.isEmpty(targetVersion)){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标版本不存在");
}
//根据版本做局部唯新校验
QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>();
if (!ObjectUtils.isEmpty(req.getVersion())){
wrapper.eq("version",req.getVersion());
wrapper.eq("target_id",targetVersion.getTargetId());
if (!ObjectUtils.isEmpty(targetVersionDao.selectList(wrapper))){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标版本号已存在");
}
}
TargetVersionConverter.INSTANCE.updateReqCopyToTargetVersion(req,targetVersion);
targetVersionService.updateById(targetVersion);
}
@Override
public InputStream fileDownload(TargetDownloadReq req) throws SftpUploadUtil.SftpUploadException {
InputStream inputStream = SftpUploadUtil.downloadFileSftp(
req.getRemoteHost(),
req.getRemotePort(),
req.getUsername(),
req.getPassword(),
req.getSshKeyPath(),
req.getRemoteFilePath()
);
return inputStream;
}
}

View File

@ -1,14 +1,20 @@
package cd.casic.ci.process.process.service.target.impl;
import cd.casic.ci.process.dal.resp.target.TargetVersionResp;
import cd.casic.ci.process.process.converter.TargetVersionConverter;
import cd.casic.ci.process.process.dal.pipeline.TargetVersionDao;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.framework.security.dal.user.AdminUserDO;
import cd.casic.framework.tenant.core.service.AdminUserServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.util.ArrayList;
import java.util.List;
@ -26,14 +32,35 @@ public class TargetVersionServiceImpl extends ServiceImpl<TargetVersionDao, Targ
@Resource
private TargetVersionDao targetVersionDao;
@Resource
private AdminUserServiceImpl adminUserService;
@Override
public List<TargetVersion> selectListByManagerId(String targetId) {
public List<TargetVersionResp> selectListByManagerId(String targetId) {
QueryWrapper<TargetVersion> wrapper = new QueryWrapper<>();
wrapper.eq("target_id",targetId);
List<TargetVersion> versionList = targetVersionDao.selectList(wrapper);
if (CollectionUtils.isEmpty(versionList)){
return new ArrayList<>(0);
}
return versionList;
List<TargetVersionResp> respList = TargetVersionConverter.INSTANCE.toRespList(versionList);
respList.forEach(this::setUserName);
return respList;
}
private void setUserName(TargetVersionResp targetVersionResp) {
if (!StringUtils.isEmpty(targetVersionResp.getCreator())){
AdminUserDO user = adminUserService.getUser(Long.valueOf(targetVersionResp.getCreator()));
if (!ObjectUtils.isEmpty(user)){
targetVersionResp.setCreatorName(user.getUsername());
}
}
if (!StringUtils.isEmpty(targetVersionResp.getUpdater())){
AdminUserDO user = adminUserService.getUser(Long.valueOf(targetVersionResp.getUpdater()));
if (!ObjectUtils.isEmpty(user)){
targetVersionResp.setUpdaterName(user.getUsername());
}
}
}
}

View File

@ -361,7 +361,6 @@ public class TemplateManagerServiceImpl extends ServiceImpl<TemplateManagerDao,
@Override
public PageResult<TemplateFindResp> findTemplatePage(TemplateQueryReq query) {
Page<TemplateFindResp> respPage = new Page<>();
QueryWrapper<TemplateManager> wrapper = new QueryWrapper<>();
if (!ObjectUtils.isEmpty(query.getId())){
@ -395,11 +394,7 @@ public class TemplateManagerServiceImpl extends ServiceImpl<TemplateManagerDao,
respList.forEach(this::setStageAndTask);
respList.forEach(this::setUserName);
respPage.setRecords(respList);
respPage.setTotal(templateManagerPage.getTotal());
respPage.setCurrent(templateManagerPage.getCurrent());
respPage.setSize(templateManagerPage.getSize());
return new PageResult<>(respList,templateManagerPage.getTotal());
return new PageResult<>(respList,templateManagerPage.getTotal(),templateManagerPage.getCurrent(),templateManagerPage.getSize());
}
@Override

View File

@ -173,9 +173,10 @@ public class SftpUploadUtil {
* @param file 本地要上传的文件路径
* @param remoteDir 远程服务器存放文件的目录 (例如: /home/user/uploads/)
* @param remoteFileName 上传到远程服务器的文件名 ( null 或空字符串时使用本地文件名)
* @return
* @throws SftpUploadException 如果上传过程中发生任何错误
*/
public static void uploadFileSftp(
public static String uploadFileSftp(
String remoteHost,
Integer remotePort,
String username,
@ -268,7 +269,7 @@ public class SftpUploadUtil {
// 8. 上传文件
channelSftp.put(fis, finalRemoteFileName);
System.out.println("文件上传成功!");
return remoteDir + "/" + finalRemoteFileName;
} catch (JSchException e) {
throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e);
} catch (SftpException e) {
@ -308,6 +309,138 @@ public class SftpUploadUtil {
}
}
/**
* 通过 SFTP 上传文件到远程服务器
*
* @param remoteHost 远程服务器IP或主机名
* @param remotePort 远程服务器端口 (通常是 22) null <= 0 时使用默认端口 22
* @param username 远程服务器用户名
* @param password 远程服务器密码 (如果使用密码认证)
* @param sshKeyPath SSH Key 文件路径 (如果使用密钥认证password 参数可以为 null)
* @param remoteFilePath 要下载的文件地址包含文件名
* @throws SftpUploadException 如果上传过程中发生任何错误
*/
public static InputStream downloadFileSftp(
String remoteHost,
Integer remotePort,
String username,
String password,
String sshKeyPath,
String remoteFilePath) throws SftpUploadException {
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
InputStream fis = null;
try {
JSch jsch = new JSch();
// 1. 添加身份认证信息 (密码或密钥)
if (sshKeyPath != null && !sshKeyPath.trim().isEmpty()) {
// 使用 SSH Key 认证
File sshKeyFile = new File(sshKeyPath);
if (!sshKeyFile.exists() || !sshKeyFile.isFile()) {
throw new SftpUploadException("SSH Key 文件不存在或不是一个有效文件: " + sshKeyPath);
}
jsch.addIdentity(sshKeyPath);
System.out.println("使用 SSH Key 认证: " + sshKeyPath);
} else if (password == null || password.trim().isEmpty()) {
// 如果没有提供密码或密钥路径则认证信息不全
throw new SftpUploadException("必须提供密码或 SSH Key 路径进行 SFTP 认证.");
}
// 如果提供了密码将在 getSession 后设置因为 getSession 需要用户名主机和端口先建立连接意图
// 2. 获取 Session
int port = (remotePort != null && remotePort > 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;
// 获取远程文件名和目录
String remoteDir = remoteFilePath.substring(0, remoteFilePath.lastIndexOf('/'));
String fileName = remoteFilePath.substring(remoteFilePath.lastIndexOf('/') + 1);
// 切换目录
channelSftp.cd(remoteDir);
// 获取文件属性判断是否为目录
SftpATTRS attrs = channelSftp.lstat(fileName);
if (attrs.isDir()) {
throw new SftpUploadException("目标路径是一个目录,无法下载: " + fileName);
}
// 获取文件流
InputStream inputStream = channelSftp.get(fileName);
if (inputStream == null) {
throw new SftpUploadException("无法获取远程文件输入流,请检查权限或路径: " + fileName);
}
return inputStream;
} catch (JSchException e) {
throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e);
} catch (SftpException e) {
throw new SftpUploadException("SFTP 操作失败 (如切换目录或上传文件): " + 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 实例