diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 8fb228bd..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 44864250..2bff8a41 100644 --- a/.gitignore +++ b/.gitignore @@ -36,5 +36,4 @@ out/ ### VS Code ### .vscode/ - .DS_Store \ No newline at end of file diff --git a/src/main/java/umc/kkijuk/server/career/controller/CareerController.java b/src/main/java/umc/kkijuk/server/career/controller/CareerController.java index 4b21e616..a31e1706 100644 --- a/src/main/java/umc/kkijuk/server/career/controller/CareerController.java +++ b/src/main/java/umc/kkijuk/server/career/controller/CareerController.java @@ -5,10 +5,11 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; +import umc.kkijuk.server.career.controller.response.CareerGroupedByResponse; import umc.kkijuk.server.career.controller.response.CareerResponse; import umc.kkijuk.server.career.controller.response.CareerResponseMessage; -import umc.kkijuk.server.career.controller.response.CareerStatusCode; import umc.kkijuk.server.career.domain.Career; import umc.kkijuk.server.career.dto.CareerRequestDto; import umc.kkijuk.server.career.dto.CareerResponseDto; @@ -23,23 +24,26 @@ @RequiredArgsConstructor @RequestMapping("/career") public class CareerController { + private final CareerService careerService; + @PostMapping("") @Operation(summary = "활동 추가 API", description = "내 커리어 - 활동을 추가하는 API") public CareerResponse create(@RequestBody @Valid CareerRequestDto.CareerDto request){ LoginUser loginUser = LoginUser.get(); Career career = careerService.createCareer(request); - return CareerResponse.success(CareerStatusCode.CREATED, + return CareerResponse.success(HttpStatus.CREATED, CareerResponseMessage.CAREER_CREATE_SUCCESS, CareerConverter.tocareerResultDto(career)); } + @DeleteMapping("/{careerId}") @Operation(summary = "활동 삭제 API", description = "내 커리어 - 활동을 삭제하는 API") @Parameter(name="careerId", description = "활동 Id, path variable 입니다.",example = "1") public CareerResponse delete(@PathVariable Long careerId){ LoginUser loginUser = LoginUser.get(); careerService.deleteCareer(careerId); - return CareerResponse.success(CareerStatusCode.OK, + return CareerResponse.success(HttpStatus.OK, CareerResponseMessage.CAREER_DELETE_SUCCESS,null); } @@ -50,20 +54,22 @@ public CareerResponse update(@RequestBody @Valid CareerRequestDto.Update @PathVariable Long careerId) { LoginUser loginUser = LoginUser.get(); Career updateCareer = careerService.updateCareer(careerId, request); - return CareerResponse.success(CareerStatusCode.OK, + return CareerResponse.success(HttpStatus.OK, CareerResponseMessage.CAREER_UPDATE_SUCCESS, - CareerConverter.toUpdateCareerResultDto(updateCareer)); + CareerConverter.toCareerDto(updateCareer)); } -// @GetMapping("") -// @Operation( -// summary = "활동 조회 API - 카테고리 기준(cateogry), 연도 기준(year) ", -// description = "내 커리어 - 활동을 카테고리 별로 조회하는 API. query 값으로 category 나 year 값을 주세요. " ) -// public CareerResponse read(@RequestParam(name="status") String value){ -// -// List careeList = careerService.getCareersGroupBy(value); -// return null; -// } + @GetMapping("") + @Operation( + summary = "활동 조회 API - category(카테고리 기준) , year(연도 기준) ", + description = "내 커리어 - 활동을 카테고리 별로 조회하는 API입니다. query 값으로 category 나 year 값을 주세요. " ) + public CareerResponse> read(@RequestParam(name="status") String value){ + List groupedCareers = careerService.getCareerGroupedBy(value); + if (!groupedCareers.isEmpty()) { + return CareerResponse.success(HttpStatus.OK, "success", groupedCareers); + } + return CareerResponse.success(HttpStatus.OK, "success", groupedCareers); + } diff --git a/src/main/java/umc/kkijuk/server/career/controller/exception/CareerExceptionControllerAdvice.java b/src/main/java/umc/kkijuk/server/career/controller/exception/CareerExceptionControllerAdvice.java index 52fdecda..7045dbee 100644 --- a/src/main/java/umc/kkijuk/server/career/controller/exception/CareerExceptionControllerAdvice.java +++ b/src/main/java/umc/kkijuk/server/career/controller/exception/CareerExceptionControllerAdvice.java @@ -24,11 +24,6 @@ public ResponseEntity> handleInvalidFormatExceptions(InvalidFo return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CareerResponse.createError(CareerResponseMessage.CAREER_FOTMAT_INVALID)); } - @ExceptionHandler(CareerNotFoundException.class) - public ResponseEntity> handleCareerNotFoundException(CareerNotFoundException e) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CareerResponse.createError(e.getMessage())); - } - @ExceptionHandler(CareerValidationException.class) public ResponseEntity> handleCareerValidationException(CareerValidationException e){ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(CareerResponse.createError(e.getMessage())); diff --git a/src/main/java/umc/kkijuk/server/career/controller/exception/CareerNotFoundException.java b/src/main/java/umc/kkijuk/server/career/controller/exception/CareerNotFoundException.java deleted file mode 100644 index 5ad92bb9..00000000 --- a/src/main/java/umc/kkijuk/server/career/controller/exception/CareerNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.kkijuk.server.career.controller.exception; - -public class CareerNotFoundException extends RuntimeException { - public CareerNotFoundException(String message) { - super(message); - } -} diff --git a/src/main/java/umc/kkijuk/server/career/controller/response/CareerGroupedByResponse.java b/src/main/java/umc/kkijuk/server/career/controller/response/CareerGroupedByResponse.java new file mode 100644 index 00000000..4595e259 --- /dev/null +++ b/src/main/java/umc/kkijuk/server/career/controller/response/CareerGroupedByResponse.java @@ -0,0 +1,4 @@ +package umc.kkijuk.server.career.controller.response; + +public abstract class CareerGroupedByResponse { +} diff --git a/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponse.java b/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponse.java index 43c01d6f..290973bb 100644 --- a/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponse.java +++ b/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponse.java @@ -49,10 +49,10 @@ public static CareerResponse createFail (BindingResult bindingResult){ errors.put(error.getObjectName(),error.getDefaultMessage()); } } - return new CareerResponse<>(CareerStatusCode.FAIL,CareerResponseMessage.CAREER_CREATE_FAIL,errors); + return new CareerResponse<>(HttpStatus.BAD_REQUEST.value(), CareerResponseMessage.CAREER_CREATE_FAIL,errors); } public static CareerResponse createError(String message){ - return new CareerResponse<>(CareerStatusCode.FAIL, message, null); + return new CareerResponse<>(HttpStatus.BAD_REQUEST.value(), message, null); } diff --git a/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponseMessage.java b/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponseMessage.java index 118f34b2..279da6c4 100644 --- a/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponseMessage.java +++ b/src/main/java/umc/kkijuk/server/career/controller/response/CareerResponseMessage.java @@ -4,13 +4,13 @@ public class CareerResponseMessage { public static final String CAREER_CREATE_SUCCESS = "활동 추가가 정상적으로 이루어졌습니다."; public static final String CAREER_UPDATE_SUCCESS = "활동 수정이 정상적으로 이루어졌습니다."; public static final String CAREER_NOT_FOUND ="존재하는 활동 Id가 아닙니다."; - public static final String CAREER_CREATE_FAIL = "활동 추가를 실패했습니다."; public static final String CAREER_FOTMAT_INVALID = "올바른 날짜 형식이 아닙니다. YYYY-MM-DD 형식으로 입력해야 합니다."; public static final String CAREER_ENDDATE = "현재 진행중이 아니라면, 활동 종료 날짜를 입력해야 합니다."; public static final String CAREER_PERIOD_FAIL = "시작 날짜는 종료 날짜보다 앞에 있어야 합니다."; public static final String CATEGORY_NOT_FOUND = "존재하는 카테고리 Id가 아닙니다."; public static final String CAREER_DELETE_SUCCESS = "활동 삭제가 정상적으로 이루어졌습니다."; + public static final String CAREER_FINDALL_FAIL = "올바른 요청이 아닙니다. category, year 요청을 주세요"; diff --git a/src/main/java/umc/kkijuk/server/career/controller/response/CareerStatusCode.java b/src/main/java/umc/kkijuk/server/career/controller/response/CareerStatusCode.java deleted file mode 100644 index b7b202ec..00000000 --- a/src/main/java/umc/kkijuk/server/career/controller/response/CareerStatusCode.java +++ /dev/null @@ -1,7 +0,0 @@ -package umc.kkijuk.server.career.controller.response; - -public class CareerStatusCode { - public static final int OK = 200; - public static final int CREATED = 201; - public static final int FAIL = 400; -} diff --git a/src/main/java/umc/kkijuk/server/career/dto/CareerResponseDto.java b/src/main/java/umc/kkijuk/server/career/dto/CareerResponseDto.java index bf9e8dbb..02fab595 100644 --- a/src/main/java/umc/kkijuk/server/career/dto/CareerResponseDto.java +++ b/src/main/java/umc/kkijuk/server/career/dto/CareerResponseDto.java @@ -5,8 +5,10 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import umc.kkijuk.server.career.controller.response.CareerGroupedByResponse; import java.time.LocalDate; +import java.util.List; public class CareerResponseDto { @@ -23,14 +25,44 @@ public static class CareerResultDto{ @Builder @NoArgsConstructor @AllArgsConstructor - public static class UpdateCareerResultDto{ + public static class CareerDto{ + Long id; String careerName; String alias; String summary; Boolean isCurrent; LocalDate startDate; LocalDate endDate; - int category; + int year; + String categoryName; + Long categoryId; + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CareerGroupedByCategoryDto extends CareerGroupedByResponse { + @Schema(description = "카테고리명",example = "동아리",type = "String") + private String category; + @Schema(description = "카테고리 내 활동 개수",example = "2",type="int") + private int count; + @Schema(description = "해당 카테고리 내 활동 목록") + private List careers; + + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CareerGroupedByYearDto extends CareerGroupedByResponse{ + @Schema(description = "연도", example = "2024", type = "int") + private int year; + @Schema(description = "연도 내 활동 개수", example = "2", type = "int") + private int count; + @Schema(description = "해당 연도 내 활동 목록") + private List careers; } diff --git a/src/main/java/umc/kkijuk/server/career/dto/converter/CareerConverter.java b/src/main/java/umc/kkijuk/server/career/dto/converter/CareerConverter.java index 7519dbbc..dc611a63 100644 --- a/src/main/java/umc/kkijuk/server/career/dto/converter/CareerConverter.java +++ b/src/main/java/umc/kkijuk/server/career/dto/converter/CareerConverter.java @@ -4,6 +4,10 @@ import umc.kkijuk.server.career.dto.CareerRequestDto; import umc.kkijuk.server.career.dto.CareerResponseDto; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + public class CareerConverter { public static Career toCareer(CareerRequestDto.CareerDto request){ @@ -22,16 +26,66 @@ public static CareerResponseDto.CareerResultDto tocareerResultDto(Career career) .careerId(career.getId()) .build(); } - public static CareerResponseDto.UpdateCareerResultDto toUpdateCareerResultDto(Career career) { - return CareerResponseDto.UpdateCareerResultDto.builder() + public static CareerResponseDto.CareerDto toCareerDto(Career career) { + return CareerResponseDto.CareerDto.builder() + .id(career.getId()) .careerName(career.getName()) .alias(career.getAlias()) .summary(career.getSummary()) .isCurrent(career.getCurrent()) .startDate(career.getStartdate()) .endDate(career.getEnddate()) - .category(Math.toIntExact(career.getCategory().getId())) + .year(career.getYear()) + .categoryId(career.getCategory().getId()) + .categoryName(career.getCategory().getName()) .build(); } + public static List toCareerGroupedByCategoryDto( Map> groupedCareers ) { + return groupedCareers.entrySet().stream() + .map(entry -> CareerResponseDto.CareerGroupedByCategoryDto.builder() + .category(entry.getKey()) + .count(entry.getValue().size()) + .careers(entry.getValue().stream() + .map(career -> CareerResponseDto.CareerDto.builder() + .id(career.getId()) + .careerName(career.getName()) + .alias(career.getAlias()) + .summary(career.getSummary()) + .year(career.getYear()) + .startDate(career.getStartdate()) + .endDate(career.getEnddate()) + .isCurrent(career.getCurrent()) + .categoryId(career.getCategory().getId()) + .categoryName(career.getCategory().getName()) + .build()) + .collect(Collectors.toList())) + .build()) + .collect(Collectors.toList()); + } + + public static List toCareerGroupedByYearDto(Map> groupedCareers) { + return groupedCareers.entrySet().stream() + .map(entry -> CareerResponseDto.CareerGroupedByYearDto.builder() + .year(Integer.parseInt(entry.getKey())) + .count(entry.getValue().size()) + .careers(entry.getValue().stream() + .map(career -> CareerResponseDto.CareerDto.builder() + .id(career.getId()) + .careerName(career.getName()) + .alias(career.getAlias()) + .summary(career.getSummary()) + .year(career.getYear()) + .startDate(career.getStartdate()) + .endDate(career.getEnddate()) + .isCurrent(career.getCurrent()) + .categoryId(career.getCategory().getId()) + .categoryName(career.getCategory().getName()) + .build()) + .collect(Collectors.toList())) + .build()) + .collect(Collectors.toList()); + } + + } diff --git a/src/main/java/umc/kkijuk/server/career/service/CareerService.java b/src/main/java/umc/kkijuk/server/career/service/CareerService.java index cdca2f17..cd8da5cc 100644 --- a/src/main/java/umc/kkijuk/server/career/service/CareerService.java +++ b/src/main/java/umc/kkijuk/server/career/service/CareerService.java @@ -1,7 +1,9 @@ package umc.kkijuk.server.career.service; +import umc.kkijuk.server.career.controller.response.CareerGroupedByResponse; import umc.kkijuk.server.career.domain.Career; import umc.kkijuk.server.career.dto.CareerRequestDto; +import umc.kkijuk.server.career.dto.CareerResponseDto; import java.util.List; import java.util.Optional; @@ -12,4 +14,5 @@ public interface CareerService { Optional findCareer(Long value); Career updateCareer(Long careerId, CareerRequestDto.UpdateCareerDto request); + List getCareerGroupedBy(String value); } diff --git a/src/main/java/umc/kkijuk/server/career/service/CareerServiceImpl.java b/src/main/java/umc/kkijuk/server/career/service/CareerServiceImpl.java index e8839f5e..81e59ce7 100644 --- a/src/main/java/umc/kkijuk/server/career/service/CareerServiceImpl.java +++ b/src/main/java/umc/kkijuk/server/career/service/CareerServiceImpl.java @@ -3,8 +3,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import umc.kkijuk.server.career.controller.exception.CareerNotFoundException; import umc.kkijuk.server.career.controller.exception.CareerValidationException; +import umc.kkijuk.server.career.controller.response.CareerGroupedByResponse; import umc.kkijuk.server.career.controller.response.CareerResponseMessage; import umc.kkijuk.server.career.domain.Career; import umc.kkijuk.server.career.dto.CareerRequestDto; @@ -12,7 +12,10 @@ import umc.kkijuk.server.career.repository.CareerRepository; import umc.kkijuk.server.career.repository.CategoryRepository; import java.time.LocalDate; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -39,6 +42,7 @@ public void deleteCareer(Long careerId) { Optional career = findCareer(careerId); careerRepository.delete(career.get()); } + @Override @Transactional public Career updateCareer(Long careerId, CareerRequestDto.UpdateCareerDto request) { @@ -66,20 +70,32 @@ public Career updateCareer(Long careerId, CareerRequestDto.UpdateCareerDto reque return careerRepository.save(career); } + @Override + public List getCareerGroupedBy(String status) { + List careers = careerRepository.findAll(); + Map> groupedCareers; + + if(status.equalsIgnoreCase("category")){ + groupedCareers = careers.stream().collect(Collectors.groupingBy(value -> value.getCategory().getName())); + return CareerConverter.toCareerGroupedByCategoryDto(groupedCareers); + } else if (status.equalsIgnoreCase("year")) { + groupedCareers = careers.stream().collect(Collectors.groupingBy(value -> String.valueOf(value.getYear()))); + return CareerConverter.toCareerGroupedByYearDto(groupedCareers); + } else { + throw new IllegalArgumentException(CareerResponseMessage.CAREER_FINDALL_FAIL); + } + } @Override public Optional findCareer(Long careerId) { return Optional.ofNullable(careerRepository.findById(careerId).orElseThrow( - () -> new CareerNotFoundException(CareerResponseMessage.CAREER_NOT_FOUND.toString()))); + () -> new CareerValidationException(CareerResponseMessage.CAREER_NOT_FOUND.toString(),"careerId"))); } - - - private void updateEndDateAndCurrentStatus(Career career, Boolean isCurrent, LocalDate endDate) { if (isCurrent != null) { career.setCurrent(isCurrent); diff --git a/src/test/java/umc/kkijuk/server/career/service/CareerServiceTest.java b/src/test/java/umc/kkijuk/server/career/service/CareerServiceTest.java index 1592dad8..c5a62407 100644 --- a/src/test/java/umc/kkijuk/server/career/service/CareerServiceTest.java +++ b/src/test/java/umc/kkijuk/server/career/service/CareerServiceTest.java @@ -10,9 +10,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.transaction.annotation.Transactional; import umc.kkijuk.server.career.controller.exception.CareerExceptionControllerAdvice; -import umc.kkijuk.server.career.controller.exception.CareerNotFoundException; import umc.kkijuk.server.career.controller.exception.CareerValidationException; import umc.kkijuk.server.career.controller.response.CareerResponse; import umc.kkijuk.server.career.controller.response.CareerResponseMessage; @@ -177,7 +175,7 @@ void init() { .build(); //when //then - assertThrows(CareerNotFoundException.class, () -> careerService.updateCareer(999L,updateCareerDto)); + assertThrows(CareerValidationException.class, () -> careerService.updateCareer(999L,updateCareerDto)); } @Test void update_수정시_날짜_형식이_잘못된_경우_에러() { @@ -230,7 +228,7 @@ void init() { //given //when //then - assertThrows(CareerNotFoundException.class, () -> careerService.deleteCareer(999L)); + assertThrows(CareerValidationException.class, () -> careerService.deleteCareer(999L)); } @Test void CareerExceptionControllerAdvice가_올바른_예외_응답을_반환하는지_검증() { diff --git a/src/test/java/umc/kkijuk/server/career/service/CareerServiceUnitTest.java b/src/test/java/umc/kkijuk/server/career/service/CareerServiceUnitTest.java index a8103025..a0f77072 100644 --- a/src/test/java/umc/kkijuk/server/career/service/CareerServiceUnitTest.java +++ b/src/test/java/umc/kkijuk/server/career/service/CareerServiceUnitTest.java @@ -6,7 +6,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import umc.kkijuk.server.career.controller.exception.CareerNotFoundException; +import umc.kkijuk.server.career.controller.exception.CareerValidationException; import umc.kkijuk.server.career.domain.Career; import umc.kkijuk.server.career.domain.Category; import umc.kkijuk.server.career.dto.CareerRequestDto; @@ -66,12 +66,12 @@ void init() { when(careerRepository.findById(anyLong())).thenReturn(Optional.empty()); //when //then - assertThrows(CareerNotFoundException.class, ()->{ + assertThrows(CareerValidationException.class, ()->{ careerService.deleteCareer(1L);}); verify(careerRepository,never()).delete(any(Career.class)); } @Test - void update_존재하지_않는_career_수정시_에러() { + void update_존재하지_않는_careerId_수정시_에러() { // given CareerRequestDto.UpdateCareerDto updateCareerDto = CareerRequestDto.UpdateCareerDto.builder() .careerName("update test") @@ -85,7 +85,7 @@ void init() { // when // then - assertThrows(CareerNotFoundException.class, () -> careerService.updateCareer(999L, updateCareerDto)); + assertThrows(CareerValidationException.class, () -> careerService.updateCareer(999L, updateCareerDto)); verify(careerRepository, never()).save(any(Career.class)); }