모델관리 목록, 삭제 API 수정된 버전 커밋

This commit is contained in:
2025-12-24 11:17:08 +09:00
parent f85d6c07b7
commit 72b8a7c41c
6 changed files with 174 additions and 143 deletions

View File

@@ -13,7 +13,12 @@ import jakarta.transaction.Transactional;
import java.time.LocalDate; import java.time.LocalDate;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "모델 관리", description = "모델 관리 API") @Tag(name = "모델 관리", description = "모델 관리 API")
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -27,42 +32,42 @@ public class ModelMngApiController {
@Operation(summary = "모델관리 목록") @Operation(summary = "모델관리 목록")
@GetMapping @GetMapping
public ApiResponseDto<Page<ModelMngDto.ModelList>> findModelMgmtList( public ApiResponseDto<Page<ModelMngDto.ModelList>> findModelMgmtList(
@RequestParam(required = false) LocalDate startDate, @RequestParam(required = false) LocalDate startDate,
@RequestParam(required = false) LocalDate endDate, @RequestParam(required = false) LocalDate endDate,
@RequestParam(required = false, defaultValue = "createCompleteDttm") String sortColumn, @RequestParam(required = false, defaultValue = "createCompleteDttm") String sortColumn,
@RequestParam(required = false) String modelType, @RequestParam(required = false) String modelType,
@RequestParam(required = false) String searchVal, @RequestParam(required = false) String searchVal,
@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) { @RequestParam(defaultValue = "20") int size) {
ModelMngDto.searchReq searchReq = new ModelMngDto.searchReq(page, size, sortColumn + ",desc"); ModelMngDto.searchReq searchReq = new ModelMngDto.searchReq(page, size, sortColumn + ",desc");
Page<ModelMngDto.ModelList> result = Page<ModelMngDto.ModelList> result =
modelMngService.findModelMgmtList(searchReq, startDate, endDate, modelType, searchVal); modelMngService.findModelMgmtList(searchReq, startDate, endDate, modelType, searchVal);
return ApiResponseDto.ok(result); return ApiResponseDto.ok(result);
} }
@Operation(summary = "삭제", description = "모델을 삭제 합니다.") @Operation(summary = "삭제", description = "모델을 삭제 합니다.")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "204", responseCode = "204",
description = "모델 삭제 성공", description = "모델 삭제 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class))), schema = @Schema(implementation = Long.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@DeleteMapping("/{modelVer}") @DeleteMapping("/{modelVer}")
public ApiResponseDto<ApiResponseDto.ResponseObj> removeModel( public ApiResponseDto<ApiResponseDto.ResponseObj> removeModel(
@io.swagger.v3.oas.annotations.parameters.RequestBody( @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "모델 삭제 요청 정보", description = "모델 삭제 요청 정보",
required = true) required = true)
@PathVariable @PathVariable
String modelVer) { String modelVer) {
return ApiResponseDto.okObject(modelMngService.removeModel(modelVer)); return ApiResponseDto.okObject(modelMngService.removeModel(modelVer));
} }
} }

View File

@@ -16,41 +16,70 @@ import org.springframework.data.domain.Sort;
public class ModelMngDto { public class ModelMngDto {
@CodeExpose
@Getter
@AllArgsConstructor
public enum ModelType implements EnumType {
M1("모델 M1"),
M2("모델 M2"),
M3("모델 M3");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Schema(name = "ModelMgmtDto Basic", description = "모델관리 엔티티 기본 정보") @Schema(name = "ModelMgmtDto Basic", description = "모델관리 엔티티 기본 정보")
@Getter @Getter
@NoArgsConstructor @NoArgsConstructor
public static class Basic { public static class Basic {
private Long modelUid;
private String modelVer; private String modelVer;
private String hyperVer;
private String epochVer;
private String dockerFileNm;
@JsonFormatDttm private ZonedDateTime createCompleteDttm; @JsonFormatDttm
@JsonFormatDttm private ZonedDateTime recentUseDttm; private ZonedDateTime createCompleteDttm;
@JsonFormatDttm
private ZonedDateTime recentUseDttm;
private Boolean deleted; private Boolean deleted;
@JsonFormatDttm private ZonedDateTime createdDttm; @JsonFormatDttm
private ZonedDateTime createdDttm;
private Long createdUid; private Long createdUid;
@JsonFormatDttm private ZonedDateTime updatedDttm; @JsonFormatDttm
private ZonedDateTime updatedDttm;
private Long updatedUid; private Long updatedUid;
private String modelType;
private String filePath;
private String fileName;
private String memo;
public Basic( public Basic(
String modelVer, Long modelUid,
String hyperVer, String modelVer,
String epochVer, ZonedDateTime createCompleteDttm,
String dockerFileNm, ZonedDateTime recentUseDttm,
ZonedDateTime createCompleteDttm, Boolean deleted,
ZonedDateTime recentUseDttm, ZonedDateTime createdDttm,
Boolean deleted, Long createdUid,
ZonedDateTime createdDttm, ZonedDateTime updatedDttm,
Long createdUid, Long updatedUid,
ZonedDateTime updatedDttm, String modelType,
Long updatedUid) { String filePath,
String fileName,
String memo
) {
this.modelUid = modelUid;
this.modelVer = modelVer; this.modelVer = modelVer;
this.hyperVer = hyperVer;
this.epochVer = epochVer;
this.dockerFileNm = dockerFileNm;
this.createCompleteDttm = createCompleteDttm; this.createCompleteDttm = createCompleteDttm;
this.recentUseDttm = recentUseDttm; this.recentUseDttm = recentUseDttm;
this.deleted = deleted; this.deleted = deleted;
@@ -58,6 +87,10 @@ public class ModelMngDto {
this.createdUid = createdUid; this.createdUid = createdUid;
this.updatedDttm = updatedDttm; this.updatedDttm = updatedDttm;
this.updatedUid = updatedUid; this.updatedUid = updatedUid;
this.modelType = modelType;
this.filePath = filePath;
this.fileName = fileName;
this.memo = memo;
} }
} }
@@ -67,17 +100,18 @@ public class ModelMngDto {
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class ModelList { public static class ModelList {
private Integer rowNum; private Integer rowNum;
private String modelVer; private String modelVer;
private String fileName; private String fileName;
private String modelType; private String modelType;
private String createCompleteDttm; private String createCompleteDttm;
private String recentUseDttm;
private BigDecimal f1Score; private BigDecimal f1Score;
private BigDecimal precision; private BigDecimal precision;
private BigDecimal recall; private BigDecimal recall;
private BigDecimal accuracy; private BigDecimal accuracy;
private BigDecimal iou; private BigDecimal iou;
private String memo;
private Boolean deleted; private Boolean deleted;
} }
@@ -112,31 +146,10 @@ public class ModelMngDto {
String[] sortParams = sort.split(","); String[] sortParams = sort.split(",");
String property = sortParams[0]; String property = sortParams[0];
Sort.Direction direction = Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property)); return PageRequest.of(page, size, Sort.by(direction, property));
} }
return PageRequest.of(page, size); return PageRequest.of(page, size);
} }
} }
@CodeExpose
@Getter
@AllArgsConstructor
public enum ModelType implements EnumType {
M1("모델 M1"),
M2("모델 M2"),
M3("모델 M3");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
} }

View File

@@ -15,16 +15,17 @@ public class ModelMngService {
private final ModelMngCoreService modelMngCoreService; private final ModelMngCoreService modelMngCoreService;
public Page<ModelMngDto.ModelList> findModelMgmtList( public Page<ModelMngDto.ModelList> findModelMgmtList(
ModelMngDto.searchReq searchReq, ModelMngDto.searchReq searchReq,
LocalDate startDate, LocalDate startDate,
LocalDate endDate, LocalDate endDate,
String modelType, String modelType,
String searchVal) { String searchVal) {
return modelMngCoreService.findModelMgmtList( return modelMngCoreService.findModelMgmtList(
searchReq, startDate, endDate, modelType, searchVal); searchReq, startDate, endDate, modelType, searchVal);
} }
public ApiResponseDto.ResponseObj removeModel(String modelVer) { public ApiResponseDto.ResponseObj removeModel(String modelVer) {
return modelMngCoreService.removeModel(modelVer); return modelMngCoreService.removeModel(modelVer);
} }
} }

View File

@@ -1,7 +1,12 @@
package com.kamco.cd.kamcoback.postgres.entity; package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
import jakarta.persistence.*; import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -11,6 +16,7 @@ import lombok.Setter;
@Entity @Entity
@Table(name = "tb_model_mng") @Table(name = "tb_model_mng")
public class ModelMngEntity extends CommonDateEntity { public class ModelMngEntity extends CommonDateEntity {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "model_uid") @Column(name = "model_uid")
@@ -43,6 +49,9 @@ public class ModelMngEntity extends CommonDateEntity {
@Column(name = "file_name") @Column(name = "file_name")
private String fileName; private String fileName;
@Column(name = "memo")
private String memo;
public void deleted() { public void deleted() {
this.deleted = true; this.deleted = true;
} }

View File

@@ -9,11 +9,12 @@ import org.springframework.data.domain.Page;
public interface ModelMngRepositoryCustom { public interface ModelMngRepositoryCustom {
Page<ModelMngDto.ModelList> findModelMgmtList( Page<ModelMngDto.ModelList> findModelMgmtList(
ModelMngDto.searchReq searchReq, ModelMngDto.searchReq searchReq,
LocalDate startDate, LocalDate startDate,
LocalDate endDate, LocalDate endDate,
String modelType, String modelType,
String searchVal); String searchVal);
Optional<ModelMngEntity> findByModelUid(String modelVer); Optional<ModelMngEntity> findByModelUid(String modelVer);
} }

View File

@@ -9,7 +9,10 @@ import com.kamco.cd.kamcoback.postgres.entity.ModelMngEntity;
import com.querydsl.core.BooleanBuilder; import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression; import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Projections; import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
@@ -26,7 +29,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
public class ModelMngRepositoryImpl extends QuerydslRepositorySupport public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
implements ModelMngRepositoryCustom { implements ModelMngRepositoryCustom {
private final JPAQueryFactory queryFactory; private final JPAQueryFactory queryFactory;
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)"); private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
@@ -38,19 +41,19 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
@Override @Override
public Page<ModelMngDto.ModelList> findModelMgmtList( public Page<ModelMngDto.ModelList> findModelMgmtList(
ModelMngDto.searchReq searchReq, ModelMngDto.searchReq searchReq,
LocalDate startDate, LocalDate startDate,
LocalDate endDate, LocalDate endDate,
String modelType, String modelType,
String searchVal) { String searchVal) {
Pageable pageable = searchReq.toPageable(); Pageable pageable = searchReq.toPageable();
Sort sort = pageable.getSort(); Sort sort = pageable.getSort();
String property = "createCompleteDttm"; // 기본으로 생성완료일 기준 String property = "createCompleteDttm"; // 기본으로 생성완료일 기준
Map<String, Expression<?>> sortColumnMap = Map<String, Expression<?>> sortColumnMap =
Map.of( Map.of(
"createCompleteDttm", modelMngEntity.createCompleteDttm, "createCompleteDttm", modelMngEntity.createCompleteDttm,
"recentUseDttm", modelMngEntity.recentUseDttm); "recentUseDttm", modelMngEntity.recentUseDttm);
if (sort.isSorted()) { if (sort.isSorted()) {
Sort.Order order = sort.iterator().next(); Sort.Order order = sort.iterator().next();
@@ -60,47 +63,46 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
Expression<?> sortColumn = sortColumnMap.get(property); Expression<?> sortColumn = sortColumnMap.get(property);
List<ModelMngDto.ModelList> foundContent = List<ModelMngDto.ModelList> foundContent =
queryFactory queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
ModelMngDto.ModelList.class, ModelMngDto.ModelList.class,
Expressions.numberTemplate( Expressions.numberTemplate(
Integer.class, "row_number() over(order by {0} desc)", sortColumn), Integer.class, "row_number() over(order by {0} desc)", sortColumn),
modelMngEntity.modelVer, modelMngEntity.modelVer,
modelMngEntity.fileName, modelMngEntity.fileName,
modelMngEntity.modelType, modelMngEntity.modelType,
Expressions.stringTemplate( Expressions.stringTemplate(
"to_char({0}, 'YYYY-MM-DD')", modelMngEntity.createCompleteDttm), "to_char({0}, 'YYYY-MM-DD')", modelMngEntity.createCompleteDttm),
Expressions.stringTemplate( roundNumericToPercent(modelResultMetricEntity.f1Score),
"to_char({0}, 'YYYY-MM-DD')", modelMngEntity.recentUseDttm), roundNumericToPercent(modelResultMetricEntity.precision),
roundNumericToPercent(modelResultMetricEntity.f1Score), roundNumericToPercent(modelResultMetricEntity.recall),
roundNumericToPercent(modelResultMetricEntity.precision), roundNumericToPercent(modelResultMetricEntity.loss),
roundNumericToPercent(modelResultMetricEntity.recall), roundNumericToPercent(modelResultMetricEntity.iou),
roundNumericToPercent(modelResultMetricEntity.loss), modelMngEntity.memo,
roundNumericToPercent(modelResultMetricEntity.iou), modelMngEntity.deleted))
modelMngEntity.deleted)) .from(modelMngEntity)
.from(modelMngEntity) .innerJoin(modelResultMetricEntity)
.innerJoin(modelResultMetricEntity) .on(modelMngEntity.modelUid.eq(modelResultMetricEntity.modelUid))
.on(modelMngEntity.modelUid.eq(modelResultMetricEntity.modelUid)) .where(
.where( eventEndedAtBetween(startDate, endDate, property),
eventEndedAtBetween(startDate, endDate, property), searchModelVersion(modelType, searchVal),
searchModelVersion(modelType, searchVal), modelMngEntity.deleted.isFalse().or(modelMngEntity.deleted.isNull()))
modelMngEntity.deleted.isFalse().or(modelMngEntity.deleted.isNull())) .offset(pageable.getOffset())
.offset(pageable.getOffset()) .limit(pageable.getPageSize())
.limit(pageable.getPageSize()) .orderBy(
.orderBy( QuerydslOrderUtil.getOrderSpecifiers(
QuerydslOrderUtil.getOrderSpecifiers( pageable, ModelMngEntity.class, "modelMngEntity"))
pageable, ModelMngEntity.class, "modelMngEntity")) .fetch();
.fetch();
Long countQuery = Long countQuery =
queryFactory queryFactory
.select(modelMngEntity.modelUid.count()) .select(modelMngEntity.modelUid.count())
.from(modelMngEntity) .from(modelMngEntity)
.where( .where(
eventEndedAtBetween(startDate, endDate, property), eventEndedAtBetween(startDate, endDate, property),
searchModelVersion(modelType, searchVal)) searchModelVersion(modelType, searchVal))
.fetchOne(); .fetchOne();
return new PageImpl<>(foundContent, pageable, countQuery); return new PageImpl<>(foundContent, pageable, countQuery);
} }
@@ -108,14 +110,14 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
@Override @Override
public Optional<ModelMngEntity> findByModelUid(String modelVer) { public Optional<ModelMngEntity> findByModelUid(String modelVer) {
return Optional.ofNullable( return Optional.ofNullable(
queryFactory queryFactory
.selectFrom(modelMngEntity) .selectFrom(modelMngEntity)
.where(modelMngEntity.modelVer.eq(modelVer)) .where(modelMngEntity.modelVer.eq(modelVer))
.fetchOne()); .fetchOne());
} }
private BooleanExpression eventEndedAtBetween( private BooleanExpression eventEndedAtBetween(
LocalDate startDate, LocalDate endDate, String sortColumn) { LocalDate startDate, LocalDate endDate, String sortColumn) {
if (Objects.isNull(startDate) || Objects.isNull(endDate)) { if (Objects.isNull(startDate) || Objects.isNull(endDate)) {
return null; return null;
} }
@@ -125,14 +127,14 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
if (sortColumn.equals("createCompleteDttm")) { if (sortColumn.equals("createCompleteDttm")) {
return modelMngEntity return modelMngEntity
.createCompleteDttm .createCompleteDttm
.goe(startDateTime.atZone(zone)) .goe(startDateTime.atZone(zone))
.and(modelMngEntity.createCompleteDttm.lt(endDateTime.atZone(zone))); .and(modelMngEntity.createCompleteDttm.lt(endDateTime.atZone(zone)));
} else { } else {
return modelMngEntity return modelMngEntity
.recentUseDttm .recentUseDttm
.goe(startDateTime.atZone(zone)) .goe(startDateTime.atZone(zone))
.and(modelMngEntity.recentUseDttm.lt(endDateTime.atZone(zone))); .and(modelMngEntity.recentUseDttm.lt(endDateTime.atZone(zone)));
} }
} }