추천

김도현·2023년 4월 26일

엔티티 변경

질문, 답변의 추천은 추천한 사람(SiteUser 객체)을 질문, 답변 엔티티에 추가해야 한다.

Question

우선 Question 엔티티에 추천인 속성을 추가해보자.

하나의 질문에 여러사람이 추천할 수 있고 한 사람이 여러 개의 질문을 추천할 수 있다. 이렇듯 질문과 추천인은 부모와 자식관계가 아니고 대등한 관계이기 때문에 @ManyToMany를 사용해야 한다.


(... 생략 ...)
import java.util.Set;
import jakarta.persistence.ManyToMany;
(... 생략 ...)
public class Question {
    (... 생략 ...)

    @ManyToMany
    Set voter;
}

Set voter 처럼 추천인을 @ManyToMany 관계로 추가했다. List가 아닌 Set으로 한 이유는 추천인은 중복되면 안되기 때문이다.

Set은 중복을 허용하지 않는 자료형이다.

Anaswer

Answer 엔티티에도 마찬가지로 추천인 속성을 추가하자

테이블 확인

질문과 답변 엔티티에 voter 속성을 추가한후 H2 콘솔을 확인해 보자.

image

QUESTION_VOTER, ANSWER_VOTER 테이블이 생성된 것을 확인할 수 있다. 이렇게 @ManyToMany 관계로 속성을 생성하면 새로운 테이블을 생성하여 데이터를 관리한다. 테이블에는 서로 연관된 엔티티의 고유번호(id) 2개가 프라이머리 키로 되어 있기 때문에 다대다 관계가 성립하는 구조이다.

질문 추천

Question 엔티티에 추천인 속성을 추가 했으니 이제 질문 추천 기능을 만들어 보자.

질문 추천 버튼

질문을 추천할 수 있는 버튼의 위치는 어디가 좋을까? 그렇다. 질문 상세 화면이다. 질문 상세 템플릿을 다음과 같이 수정하자.

image

질문의 추천 버튼을 질문의 수정 버튼 좌측에 추가했다. 그리고 버튼에는 추천수도 함께 보이도록 했다. 추천 버튼을 클릭하면 href의 속성이 javascript:void(0) 으로 되어 있기 때문에 아무런 동작도 하지 않는다. 하지만 클래스 속성에 "recommend"를 추가하여 자바스크립트를 사용하여 data-uri에 정의된 url이 호출되도록 할 것이다. 이와 같은 방법을 사용하는 이유는 "추천" 버튼을 눌렀을때 확인창을 통해 사용자의 확인을 구하기 위함이다.

추천 버튼 확인 창

이어서 <추천> 버튼을 클릭했을 때 '정말로 추천하시겠습니까?'라는 확인 창이 나타나야 하므로 다음 코드를 추가하자.

image

추천 버튼에 class="recommend"가 적용되어 있으므로 추천 버튼을 클릭하면 "정말로 추천하시겠습니까?"라는 질문이 나타나고 "확인"을 선택하면 data-uri 속성에 정의한 URL이 호출될 것이다.

QuestionService

그리고 추천인을 저장하기 위해 다음과 같이 QuestionService를 수정하자.


(... 생략 ...)
public class QuestionService {

    (... 생략 ...)

    public void vote(Question question, SiteUser siteUser) {
        question.getVoter().add(siteUser);
        this.questionRepository.save(question);
    }
}

Question 엔티티에 사용자를 추천으로 저장하는 vote 메서드를 추가했다.

QuestionController

이제 추천 버튼을 눌렀을때 호출되는 URL을 처리하기 위해 다음과 같이 QuestionController를 수정하자.


(... 생략 ...)
public class QuestionController {

    (... 생략 ...)

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/vote/{id}")
    public String questionVote(Principal principal, @PathVariable("id") Integer id) {
        Question question = this.questionService.getQuestion(id);
        SiteUser siteUser = this.userService.getUser(principal.getName());
        this.questionService.vote(question, siteUser);
        return String.format("redirect:/question/detail/%s", id);
    }
}

위와 같이 questionVote 메서드를 추가했다. 추천은 로그인한 사람만 가능해야 하므로 @PreAuthorize("isAuthenticated()") 어노테이션이 적용되었다. 그리고 위에서 작성한 QuestionService의 vote 메서드를 호출하여 추천인을 저장했다. 오류가 없다면 질문 상세화면으로 리다이렉트 한다.

답변 추천

답변 추천 기능은 질문 추천 기능과 동일하므로 빠르게 작성해 보자.

답변 추천 버튼

답변의 추천수를 표시하고, 답변을 추천할 수있는 버튼을 질문 상세 템플릿에 다음과 같이 추가하자.

image

질문과 마찬가지로 답변 영역의 상단에 답변을 추천할 수 있는 버튼을 생성했다. 이 역시 추천 버튼에 class="recommend"가 적용되어 있으므로 추천 버튼을 클릭하면 "정말로 추천하시겠습니까?"라는 질문이 나타나고 "확인"을 선택하면 data-uri 속성에 정의한 URL이 호출될 것이다

AnswerService

그리고 답변에 추천인을 저장하기 위해 다음과 같이 AnswerService를 수정하자.


(... 생략 ...)
public class AnswerService {

    (... 생략 ...)

    public void vote(Answer answer, SiteUser siteUser) {
        answer.getVoter().add(siteUser);
        this.answerRepository.save(answer);
    }
}

Answer 엔티티에 사용자를 추천인으로 저장하는 vote 메서드를 추가했다.

AnswerController

이제 답변 추천 버튼을 눌렀을때 호출되는 URL을 처리하기 위해 다음과 같이 AnswerController를 수정하자


(... 생략 ...)
public class AnswerController {

    (... 생략 ...)

    @PreAuthorize("isAuthenticated()")
    @GetMapping("/vote/{id}")
    public String answerVote(Principal principal, @PathVariable("id") Integer id) {
        Answer answer = this.answerService.getAnswer(id);
        SiteUser siteUser = this.userService.getUser(principal.getName());
        this.answerService.vote(answer, siteUser);
        return String.format("redirect:/question/detail/%s", answer.getQuestion().getId());
    }
}

위와 같이 answerVote 메서드를 추가했다. 추천은 로그인한 사람만 가능해야 하므로 @PreAuthorize("isAuthenticated()") 애너테이션이 적용되었다. 그리고 위에서 작성한 AnswerService의 vote 메서드를 호출하여 추천인을 저장한다. 오류가 없다면 질문 상세화면으로 리다이렉트 한다.

profile
Just do it

0개의 댓글