
Modal 컴포넌트 리팩토링 이후, 확인 Modal을 사용하는 삭제 기능에서 오류 발생
현재
전역예외처리 핸들러를 사용하고 있었고 반환된 에러 내용은 대강
status:INTERNAL_SEVER_ERROR
message:POST NOT FOUND
로 반환되고 있었다. modal 이 닫히지 않고
redirect 처리는 이루어지지 않고 있었다.
백엔드 예외처리 로직
해당 예외처리 핸들러에 예외처리 클래스가 몇 개 더 명시 되어 있었지만
Post Service에서orElseThorw하고 있는RuntimeExcetpion에 대한 예외처리 클래스는 명시 하지 않아 모든 예외처리를 일괄 담당하는 아래Exception.class가INTERNAL_SEVER_ERROR를 반환했다.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
ErrorResponse error = ErrorResponse.builder()
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.message(e.getMessage())
.redirect("/")
.build();
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
아래 백엔드 삭제 컨트롤러와 서비스 로직을 살펴 보면
remove가 동작하게 되면postService.remove(id)부분에서post Entity를 삭제 처리 후에 삭제된 이미지 명을 반환하기 위해oldFileNames객체에서postService에서get요청을 하고있다.
따라서 실제 게시물 삭제 까지는 이루어지지만 500Error를 반환 하는 것이다.
#컨트롤러
@DeleteMapping("/{id}")
public ResponseEntity<?> remove(
@PathVariable Long id,
@AuthenticationPrincipal UserDTO principal) {
postService.checkAuthorization(id, principal.getEmail());
postService.remove(id);
List<String> oldFileNames = postService.get(id).getImageList();
return ResponseEntity.ok(Map.of("result", "success", "oldFileNames", oldFileNames));
}
#서비스 삭제 로직
@Override
@Caching(evict = {@CacheEvict(value = "post", key = "#id"), @CacheEvict(value = "postComments", key = "#id")})
@Transactional
public void remove(Long id) {
Post post = postRepository.findById(id).orElseThrow(()-> new RuntimeException("Post not found"));
deleteFiles(post.getImageList());
postRepository.deleteById(id);
}
#서비스 겟 로직
@Override
public PostDTO get(Long id) {
Post post = postRepository.findById(id).orElseThrow(() -> new RuntimeException("Post not found"));
PostDTO dto = entityToDTO(post);
dto.setImageList(post.getImageList().stream()
.map(image -> addPrefix(image.getFileName()))
.collect(Collectors.toList()));
dto.setExistingImageUrls(new ArrayList<>(dto.getImageList()));
return dto;
}
보시다시피 get 에서도 해당 post 를 찾을 수 없으면 예외를 반환하도록 설정되어 있다.
프론트 코드
const delMutation = useMutation({
mutationFn: (postId) => deleteOne(postId),
onSuccess: () => {
closeModal();
// 삭제된 게시물의 캐시는 제거하되 refetch는 하지 않음
queryClient.removeQueries({
queryKey: ['post', postId],
refetchType: 'none'
});
// 리스트는 refetch하여 최신 상태 유지
queryClient.invalidateQueries({
queryKey: ['post/List']
});
moveToList();
},
onError: (error) => {
console.error("삭제 중 에러 발생:", error);
alert("게시물 삭제 중 오류가 발생했습니다.");
closeModal();
}
});
removeQueries가refetch를 유발하지 않지만 명시적으로 적어 주었다.inavalidateQueries를 통해post/List를refetch해 해당 게시물이 지워진List를 새로 받은 후moveToList가 작동하도록 설정 했다.
프론트 axios.interceptor 부분
정리를 하면서 프론트 부분에서 INTERNAL_SERVER_ERROR 발생시엔 Redirect 처리를 하지 않은 부분도 확인 했다.(추후 수정 예정)
const handleErrorResponse = ({message, redirect, errorStatus}) => {
console.error(`Error: ${errorStatus}, Message: ${message}`);
switch (errorStatus) {
case ERROR_TYPES.AUTHENTICATION_REQUIRED:
case ERROR_TYPES.AUTHENTICATION_FAILED:
case ERROR_TYPES.INSUFFICIENT_AUTHENTICATION:
handleRedirect(redirect, REDIRECT_PATHS.LOGIN);
break;
case ERROR_TYPES.ACCESS_DENIED:
handleRedirect(redirect, REDIRECT_PATHS.ERROR);
break;
case ERROR_TYPES.NEED_PROFILE_UPDATE:
handleRedirect(redirect, REDIRECT_PATHS.MODIFY);
break;
}
};
최종 수정 코드
@DeleteMapping("/{id}")
public ResponseEntity<?> remove(
@PathVariable Long id,
@AuthenticationPrincipal UserDTO principal) {
postService.checkAuthorization(id, principal.getEmail());
List<String> oldFileNames = postService.get(id).getImageList();
postService.remove(id);
return ResponseEntity.ok(Map.of("result", "success", "oldFileNames", oldFileNames));
}
단순히 필요한 정보를 모두 조회 후 삭제하는 것 만으로 오류 해결. 간단한 문제를 리액트 쿼리 관련 문제인 줄 알고 헤맸다.