늦은 프로그래밍 이야기
230105 TIL 본문
팀프로젝트
계층형 카테고리
@Getter 어노테이션의 부재로 인해 발생한 HttpMessageConversionException 에러 해결
어제 만들었던 계층형 카테고리에서 카테고리를 조회할 때 이중 for문에 재귀함수까지 사용을 해서 자식 카테고리가 늘어날 수록 이중 for문이 삼중 for문이 되고 점점 같이 늘어날 수 있다는 피드백을 받게 되었다.
새로운 조회 방법을 생각해보다가 일반적으로 사용되는 부모 카테고리를 클릭 했을 때 자식 카테고리들이 보여지는 형태로 구현을 하고자 했다. 새로운 Controller 메소드를 만들고 부모 categoryId 값을 파라미터로 넘겨준다.
@GetMapping("/categories/{categoryId}")
publicList<CategoryResponseDto> getChildrenCategories(@PathVariable Long categoryId) {
return categoryService.getChildrenCategory(categoryId);
}
받아온 부모 카테고리의 id로 부모 카테고리를 조회한 후 부모 카테고리의 layer 값에 + 1 한 값으로 자식 카테고리들을 조회하고 해당 카테고리들의 리스트를 각각 CategoryResponseDto에 담아 반환 해주었다.
publicList<CategoryResponseDto> getChildrenCategory(Long categoryId) {
Category category = categoryRepository.findByCategoryId(categoryId).orElseThrow(
() -> new IllegalArgumentException("존재하지 않는 카테고리입니다.")
);
List<Category> childrenCategoryList = categoryRepository.getCategoriesByLayer(category.getLayer() + 1);
return childrenCategoryList.stream().map(childrenCategory -> new CategoryResponseDto(childrenCategory)).collect(Collectors.toList());
}
코드를 완성해고 테스트를 해보았는데, HttpMessageConversionException: Type definition error: [simple type, class com.postproject.dto.CategoryResponseDto] 발생하며 조회가 되지 않았다. 해당 에러 메시지를 구글링하여 정보를 찾아본 결과 CategoryResponseDto에 @Getter 어노테이션이 누락되어서 JSON으로 파싱이 불가해서 발생한 문제였다. JSON으로 파싱하기 위해 사용하는 Jackson의 입장에서 값을 읽을 수 없기 때문이라고 한다. @Getter 어노테이션을 달아주니 문제가 해결되었다.
부모 카테고리로 자식 카테고리를 조회 시 다른 자식 카테고리들이 조회되는 문제
위에서 자식 카테고리들을 조회할 때 잘못 생각해서 layer로 조회를 하였는데 자식 카테고리들이 parent 값을 가지고 있기 때문에 layer로 조회할 필요 없이 parent 값으로 조회를 하면 선택한 부모 카테고리의 자식 카테고리들만 나올 것이다.
publicList<CategoryResponseDto> getChildrenCategory(Long categoryId) {
Category category = categoryRepository.findByCategoryId(categoryId).orElseThrow(
() -> new IllegalArgumentException("존재하지 않는 카테고리입니다.")
);
List<Category> childrenCategoryList = categoryRepository.getCategoriesByParent(category.getName());
return childrenCategoryList.stream().map(childrenCategory -> new CategoryResponseDto(childrenCategory)).collect(Collectors.toList());
}
layer 값으로 자식 카테고리를 조회하는 것을 parent 값으로 조회를 하니 해당 부모 카테고리의 자식 카테고리들만 조회가 되었다.
카테고리 계층을 3계층으로 제한
팀원의 의견에 따라 카테고리 계층을 무제한에서 3계층으로 제한하였다. Category 엔티티의 layer의 최대값을 2로 제한하여 카테고리를 최대 3계층까지만 생성할 수 있도록 제한하였다.
@Max(value = 2, message = "카테고리 계층은 최대 3까지 가능합니다.")
@Column(nullable = false)
private int layer = 0;
카테고리를 3계층을 초과하여 생성할 때 발생하는 ConstraintViolationException의 예외처리
RestControllerAdvice의 클래스에 일반적인 예외처리와 동일하게 BAD_REQUEST 값을 줘서 예외처리를 하였는데 MethodArgumentNotValidException과 같이 e.getMessage가 깔끔하게 나오지 않는 모습이었다.
@ExceptionHandler(ConstraintViolationException.class)
private ResponseEntity<StatusResponseDto> ConstraintViolationExceptionHandler(ConstraintViolationException e){
StatusResponseDto statusResponseDto = new StatusResponseDto(HttpStatus.BAD_REQUEST.value(),e.getMessage());
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(new MediaType("application","json", Charset.forName("UTF-8")));
return new ResponseEntity<>(statusResponseDto,httpHeaders,HttpStatus.BAD_REQUEST);
}
해당 Exception의 이름을 구글링 해보며 다양한 방법을 시도해 보았지만, 우리가 작성한 폼과 달라서 적용하기가 힘들었다. 그러던 중 하나의 글을 보고 stream으로 해당 메시지가 속해있는 HashSet을 리스트로 변경하는 방법으로 message를 변수에 담아주고 출력 해주었다.
@ExceptionHandler(ConstraintViolationException.class)
private ResponseEntity<StatusResponseDto> ConstraintViolationExceptionHandler(ConstraintViolationException e){
String message = e.getConstraintViolations()
.stream()
.map(ConstraintViolation::getMessage)
.toList()
.get(0);
StatusResponseDto statusResponseDto = new StatusResponseDto(HttpStatus.BAD_REQUEST.value(), message);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(new MediaType("application","json", Charset.forName("UTF-8")));
return new ResponseEntity<>(statusResponseDto,httpHeaders,HttpStatus.BAD_REQUEST);
MethodArgumentNotValidException이나 ConstraintViolationException 같이 특수한 경우의 메시지를 핸들링 하는 방법을 기록해 두던지 어떠한 로직에 의해서 메시지만 가져올 수 있는 것인지 찾아보고 공부하여야 할 것이다.
Git
오늘 진행한 부분을 main레파지토리의 dev브랜치에 push하는 과정에서 add를 하고 commit 없이 push를 해버려서 여태 작업했던 내용들이 날라가는 불상사가 발생하였다. Git을 잘하는 팀원의 도움을 받아서 Rebase를 취소해 보았다.
Rebase를 취소하는 방법
잘못 리베이스 된 git이 remote repo까지 반영된 경우, reflog와 reset을 사용하면 된다.
git reflog 브랜치명
잘못 리베이스한 로컬 컴퓨터에서 실행하여 리베이스 로그를 볼 수 있다.
git reset --hard [HEAD@{숫자}앞의 7자리]
reflog에서 HEAD@{숫자}의 앞의 7자리 숫자문자로 돌아가고 싶은 커밋명을 입력하여 커밋 이력을 모두 reset한다.
git push -f repo명 브랜치명
리셋한 커밋 이력을 remote로 강제 푸시를 해야한다.
협업에 사용되는 git 명령어가 흩어져서 정리되어 있는데 한 곳에 모아 정리하고 궁금한 것들은 검색해보고 추가하면서 다음 프로젝트에서도 계속 사용하도록 해서 git 터미널 명령어에 익숙해지도록 해야할 것이다.
'내일배움캠프 > TIL, WIL' 카테고리의 다른 글
| 10주차 WIL (0) | 2023.01.09 |
|---|---|
| 230106 TIL (KPT 회고) (0) | 2023.01.06 |
| 230104 TIL (계층형 카테고리) (0) | 2023.01.05 |
| 230103 TIL (0) | 2023.01.04 |
| 230102 TIL (0) | 2023.01.02 |