개발일지/2023_한이음

🤦🏻‍♀️고민하기 - 중복되는 코드 리팩토링 - 피드백 게시판 CRUD

기억지기 개발자 2023. 10. 25. 14:27

🏕️상황

  • 게시판의 형식으로 (개발 관련해서) 웹 사이트의 오류, 개선사항, 에러 발견 등의 사항들을 올릴 수 있도록 개발하는 것이 목표였다.
  • 게시글에 대한 권한 부여를 어떻게 구현할 것인지 살짝 고민이 되었지만 spring security를 사용하지 않아도 복잡하거나 어렵지 않게 구현할 수 있을 거 같아 일단은 단편적인 방법으로 구현하기로 했다.
  • 기능 개발을 다 하고 보니 여러 메서드들에 공통적으로 사용되는 부분이 있었고, 그걸 보니 최근에 배운 내용이 생각났다. (아래와 같은) 🔽
공통적으로 사용되는 부분은 끄집어 내서 따로 정의한다.

 

⭐리팩토링 전 코드

@Service
public class feedbackService {
    @Autowired
    private feedbackRepository repository;

    // 하나의 피드백 정보를 가지고 옴. (게시글 작성자 or 관리자만 볼 수 있음)
    public ResponseDTO<Optional<FeedbackBoard>> getFeedback(Long id, User user) {
        try {
            Optional<FeedbackBoard> feedbackOptional = repository.findById(id);

            if (feedbackOptional.isPresent()) {
                FeedbackBoard feedback = feedbackOptional.get();

                if (user.getId() == feedback.getUser().getId() || user.getRole() == 1) {
                    return ResponseDTO.success(feedbackOptional);
                } else {
                    return ResponseDTO.fail("Unauthorized", "You are not authorized to access this feedback.");
                }
            } else {
                return ResponseDTO.fail("Not Found", "Feedback with ID " + id + " not found.");
            }
        } catch (Exception e) {
            String error = e.getMessage();
            return ResponseDTO.fail("Error", error);
        }
    }

    // 접근 권한이 있는 사용자만 해당 글을 수정할 수 있음.
    public ResponseDTO<?> updateFeedback(feedbackDTO updatedFeedback,Long id, User user) {
        try {
            Optional<FeedbackBoard> feedbackOptional = repository.findById(id);

            if (feedbackOptional.isPresent()) {
                FeedbackBoard feedback = feedbackOptional.get();

                // 사용자의 ID와 피드백 게시물의 사용자 ID가 일치하거나 사용자의 역할이 1인 경우에만 수정 허용
                if (user.getId() == feedback.getUser().getId() || user.getRole() == 1) {
                    // 엔티티 필드 업데이트
                    feedback.setTitle(updatedFeedback.getTitle());
                    feedback.setContent(updatedFeedback.getContent());
                    feedback.setCategory(updatedFeedback.getCategory());
                    feedback.setResponse(updatedFeedback.getResponse());

                    // 변경 사항을 데이터베이스에 저장
                    repository.save(feedback);

                    return ResponseDTO.success(feedback);
                } else {
                    return ResponseDTO.fail("Unauthorized", "You are not authorized to update this feedback.");
                }
            } else {
                return ResponseDTO.fail("Not Found", "Feedback not found.");
            }
        } catch (Exception e) {
            String error = e.getMessage();
            return ResponseDTO.fail("Error", error);
        }
    }

    public ResponseDTO<?> deleteFeedback(Long id, User user) {
        try {
            Optional<FeedbackBoard> feedbackOptional = repository.findById(id);

            if (feedbackOptional.isPresent()) {
                FeedbackBoard feedback = feedbackOptional.get();

                // 사용자의 ID와 피드백 게시물의 사용자 ID가 일치하거나 사용자의 역할이 1인 경우에만 삭제 허용
                if (user.getId() == feedback.getUser().getId() || user.getRole() == 1) {
                    // 피드백 게시물 삭제
                    repository.delete(feedback);

                    return ResponseDTO.success("Feedback deleted successfully.");
                } else {
                    return ResponseDTO.fail("Unauthorized", "You are not authorized to delete this feedback.");
                }
            } else {
                return ResponseDTO.fail("Not Found", "Feedback not found.");
            }
        } catch (Exception e) {
            String error = e.getMessage();
            return ResponseDTO.fail("Error", error);
        }
    }

}

 

 

🗝️리팩토링 후 코드

@Service
public class feedbackService {
    @Autowired
    private feedbackRepository repository;

    // update 기능 (권한 필요 O)
    public ResponseDTO<?> updateFeedback(feedbackDTO updatedFeedback, Long id, User user) {
        return processFeedbackRequest(id, user, feedback -> {

            feedback.setTitle(updatedFeedback.getTitle());
            feedback.setContent(updatedFeedback.getContent());
            feedback.setCategory(updatedFeedback.getCategory());
            feedback.setResponse(updatedFeedback.getResponse());

            repository.save(feedback);

            return ResponseDTO.success(feedback);
        });
    }

    // 피드백 1개 상세조회 (권한 필요 O)
    public ResponseDTO<?> getFeedback(Long id, User user) {
        return processFeedbackRequest(id, user, feedback -> {
            return ResponseDTO.success(Optional.of(feedback));
        });
    }

    // 피드백 삭제 (권한 필요 O)
    public ResponseDTO<?> deleteFeedback(Long id, User user) {
        return processFeedbackRequest(id, user, feedback -> {

            repository.delete(feedback);

            return ResponseDTO.success("Feedback deleted successfully.");
        });
    }

    // 사용자 권한 여부를 판단하는 메소드
    // 중복을 줄이기 위해서 정의한 메소드
    public ResponseDTO<?> processFeedbackRequest(Long id, User user, Function<FeedbackBoard, ResponseDTO<?>> action) {
        try {
            Optional<FeedbackBoard> feedbackOptional = repository.findById(id);

            return feedbackOptional.map(feedback -> {
                //여기에 있는 feedback은 feedbackOptional를 복제해온 객체이다. (현재 feedback = feedbackOptional)
                // 동일한 객체인 feedback을 가지고 아래의 코드에서 원하는 작업을 진행한다. 
                if (user.getId() == feedback.getUser().getId() || user.getRole() == 1) {
                    return action.apply(feedback);
                } else {
                    return ResponseDTO.fail("Unauthorized", "You are not authorized to access this feedback.");
                }
            }).orElseGet(() -> ResponseDTO.fail("Not Found", "Feedback with ID " + id + " not found."));
            //.orElseGet() 메서드는 Optional이 비어있을 때 대체 값을 생성하는 데 사용
        } catch (Exception e) {
            String error = e.getMessage();
            return ResponseDTO.fail("Error", error);
        }
    }
}

 



Function<FeedbackBoard, ResponseDTO<?>> action

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
  • Function은 Java의 함수형 프로그래밍을 지원하는 인터페이스 중 하나로,  java의 'java.util.function' 패키지에 포함되어 있다. 
  • T : 입력 형식(parameter type)을 나타낸다.
  • R : 반환 값 형식(return type)을 나타낸다.
  • FeedbackBoard를 입력받아 ResponseDTO<?>를 반환하는 함수이다.