diff --git a/src/main/java/com/brainpix/profile/controller/PortfolioController.java b/src/main/java/com/brainpix/profile/controller/PortfolioController.java index 5ddd128a..10e81bdc 100644 --- a/src/main/java/com/brainpix/profile/controller/PortfolioController.java +++ b/src/main/java/com/brainpix/profile/controller/PortfolioController.java @@ -16,6 +16,7 @@ import com.brainpix.api.ApiResponse; import com.brainpix.api.CommonPageResponse; +import com.brainpix.api.swagger.SwaggerPageable; import com.brainpix.profile.dto.CreatePortfolioDto; import com.brainpix.profile.dto.request.PortfolioRequest; import com.brainpix.profile.dto.response.PortfolioDetailResponse; @@ -26,6 +27,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @RestController @@ -41,7 +43,7 @@ public class PortfolioController { @PostMapping public ResponseEntity> createPortfolio( @UserId Long userId, - @RequestBody PortfolioRequest request + @Valid @RequestBody PortfolioRequest request ) { Long portfolioId = portfolioService.createPortfolio(userId, request); @@ -55,7 +57,7 @@ public ResponseEntity> createPortfolio( public ResponseEntity> updatePortfolio( @UserId Long userId, @PathVariable long portfolioId, - @RequestBody PortfolioRequest request + @Valid @RequestBody PortfolioRequest request ) { try { portfolioService.updatePortfolio(userId, portfolioId, request); @@ -79,6 +81,7 @@ public ResponseEntity> deletePortfolio( @AllUser @Operation(summary = "내 포트폴리오 목록 조회", description = "사용자 ID를 기준으로 포트폴리오 목록을 페이징 처리하여 조회합니다.") @GetMapping + @SwaggerPageable public ResponseEntity> findMyPortfolios( @UserId Long userId, @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable diff --git a/src/main/java/com/brainpix/profile/dto/request/PortfolioRequest.java b/src/main/java/com/brainpix/profile/dto/request/PortfolioRequest.java index 8ba0fd4b..56e36578 100644 --- a/src/main/java/com/brainpix/profile/dto/request/PortfolioRequest.java +++ b/src/main/java/com/brainpix/profile/dto/request/PortfolioRequest.java @@ -2,19 +2,33 @@ import java.time.YearMonth; import java.util.List; +import java.util.Optional; + +import org.springframework.format.annotation.DateTimeFormat; import com.brainpix.profile.entity.Portfolio; import com.brainpix.profile.entity.Profile; import com.brainpix.profile.entity.Specialization; import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; + public record PortfolioRequest( + @NotBlank(message = "포트폴리오 제목을 입력해주세요.") String title, - List specializations, + List specializations, + @NotBlank(message = "시작 날짜를 입력해주세요.") + @Schema(type = "string", example = "yyyy-MM") + @DateTimeFormat(pattern = "yyyy-MM") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM") YearMonth startDate, + @NotBlank(message = "종료 날짜를 입력해주세요.") + @Schema(type = "string", example = "yyyy-MM") + @DateTimeFormat(pattern = "yyyy-MM") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM") YearMonth endDate, + @NotBlank(message = "포트폴리오 내용을 입력해주세요.") String content, String profileImage ) { @@ -23,14 +37,11 @@ public record PortfolioRequest( * DTO -> Entity 변환 (생성 시 사용) */ public Portfolio toEntity(Profile profile) { - List specs = specializations.stream() - .map(SpecializationRequest::toDomain) - .toList(); return Portfolio.create( profile, title, - specs, + specializations, startDate, endDate, content, @@ -42,17 +53,14 @@ public Portfolio toEntity(Profile profile) { * 엔티티 수정에 반영할 메서드 (update) */ public void applyTo(Portfolio portfolio) { - List specs = specializations.stream() - .map(SpecializationRequest::toDomain) - .toList(); portfolio.update( - title, - specs, - startDate, - endDate, - content, - profileImage + Optional.ofNullable(title).orElse(portfolio.getTitle()), // null이면 기존 값 유지 + Optional.ofNullable(specializations).orElse(portfolio.getSpecializationList()), // null이면 기존 값 유지 + Optional.ofNullable(startDate).orElse(portfolio.getStartDate()), + Optional.ofNullable(endDate).orElse(portfolio.getEndDate()), + Optional.ofNullable(content).orElse(portfolio.getContent()), + Optional.ofNullable(profileImage).orElse(portfolio.getProfileImage()) ); } } \ No newline at end of file diff --git a/src/main/java/com/brainpix/profile/dto/request/SpecializationRequest.java b/src/main/java/com/brainpix/profile/dto/request/SpecializationRequest.java index e34a5a56..d14c7d6a 100644 --- a/src/main/java/com/brainpix/profile/dto/request/SpecializationRequest.java +++ b/src/main/java/com/brainpix/profile/dto/request/SpecializationRequest.java @@ -1,20 +1,12 @@ package com.brainpix.profile.dto.request; -import com.brainpix.api.code.error.CommonErrorCode; -import com.brainpix.api.exception.BrainPixException; import com.brainpix.profile.entity.Specialization; -public record SpecializationRequest(String specialization) { +import jakarta.validation.constraints.NotNull; - public Specialization toDomain() { - if (specialization == null || specialization.trim().isEmpty()) { - throw new BrainPixException(CommonErrorCode.RESOURCE_NOT_FOUND); - } +public record SpecializationRequest(@NotNull(message = "전문 분야는 필수 입력값입니다.") Specialization specialization) { - try { - return Specialization.of(specialization); - } catch (BrainPixException e) { - throw new BrainPixException(CommonErrorCode.RESOURCE_NOT_FOUND); - } + public Specialization toDomain() { + return specialization; } } diff --git a/src/main/java/com/brainpix/profile/dto/response/PortfolioDetailResponse.java b/src/main/java/com/brainpix/profile/dto/response/PortfolioDetailResponse.java index 58728a4a..d6bb47ba 100644 --- a/src/main/java/com/brainpix/profile/dto/response/PortfolioDetailResponse.java +++ b/src/main/java/com/brainpix/profile/dto/response/PortfolioDetailResponse.java @@ -1,29 +1,41 @@ package com.brainpix.profile.dto.response; +import java.time.YearMonth; import java.util.List; +import org.springframework.format.annotation.DateTimeFormat; + import com.brainpix.profile.entity.Portfolio; +import com.brainpix.profile.entity.Specialization; +import com.fasterxml.jackson.annotation.JsonFormat; + +import io.swagger.v3.oas.annotations.media.Schema; public record PortfolioDetailResponse( long id, String title, - List specializations, - String startDate, - String endDate, + List specializations, + @Schema(type = "string", example = "yyyy-MM") + @DateTimeFormat(pattern = "yyyy-MM") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM") + YearMonth startDate, + + @Schema(type = "string", example = "yyyy-MM") + @DateTimeFormat(pattern = "yyyy-MM") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM") + YearMonth endDate, String content, String profileImage ) { public static PortfolioDetailResponse of(Portfolio portfolio) { - List specs = portfolio.getSpecializationList().stream() - .map(Enum::name) - .toList(); + List specs = portfolio.getSpecializationList(); return new PortfolioDetailResponse( portfolio.getId(), portfolio.getTitle(), specs, - portfolio.getStartDate().toString(), - portfolio.getEndDate().toString(), + portfolio.getStartDate(), + portfolio.getEndDate(), portfolio.getContent(), portfolio.getProfileImage() ); diff --git a/src/main/java/com/brainpix/profile/dto/response/PortfolioResponse.java b/src/main/java/com/brainpix/profile/dto/response/PortfolioResponse.java index c79e1276..b960902b 100644 --- a/src/main/java/com/brainpix/profile/dto/response/PortfolioResponse.java +++ b/src/main/java/com/brainpix/profile/dto/response/PortfolioResponse.java @@ -1,12 +1,12 @@ package com.brainpix.profile.dto.response; -import java.time.LocalDateTime; +import java.time.LocalDate; import com.brainpix.profile.entity.Portfolio; public record PortfolioResponse(long id, String title, - LocalDateTime createdDate, + LocalDate createdDate, String profileImage ) { @@ -14,7 +14,7 @@ public static PortfolioResponse from(Portfolio portfolio) { return new PortfolioResponse( portfolio.getId(), portfolio.getTitle(), - portfolio.getCreatedAt(), + portfolio.getCreatedAt().toLocalDate(), portfolio.getProfileImage() ); } diff --git a/src/main/java/com/brainpix/profile/entity/Portfolio.java b/src/main/java/com/brainpix/profile/entity/Portfolio.java index f55d4de0..c2e3f05f 100644 --- a/src/main/java/com/brainpix/profile/entity/Portfolio.java +++ b/src/main/java/com/brainpix/profile/entity/Portfolio.java @@ -4,6 +4,7 @@ import java.util.List; import com.brainpix.api.code.error.PortfolioErrorCode; +import com.brainpix.api.exception.BrainPixException; import com.brainpix.jpa.BaseTimeEntity; import com.brainpix.user.entity.User; @@ -83,9 +84,7 @@ public void update(String title, List specializationList, YearMo public void validateOwnership(User user) { if (!this.profile.getUser().equals(user)) { - throw new IllegalArgumentException( - PortfolioErrorCode.NOT_OWNED_PORTFOLIO.getMessage() - ); + throw new BrainPixException(PortfolioErrorCode.NOT_OWNED_PORTFOLIO); } } } diff --git a/src/main/java/com/brainpix/profile/entity/Specialization.java b/src/main/java/com/brainpix/profile/entity/Specialization.java index 3ec67b5b..dda900da 100644 --- a/src/main/java/com/brainpix/profile/entity/Specialization.java +++ b/src/main/java/com/brainpix/profile/entity/Specialization.java @@ -15,16 +15,4 @@ public enum Specialization { IT_TECH, // IT · 테크 OTHERS; //기타 - public static Specialization of(String name) { - if (name == null) { - throw new IllegalArgumentException("Specialization cannot be null."); - } - try { - // valueOf로 매칭된 enum 반환 - return Specialization.valueOf(name.toUpperCase()); - } catch (IllegalArgumentException e) { - // 그 외 값은 예외 발생 - throw new IllegalArgumentException("Invalid Specialization: " + name); - } - } }