질문 1개 GET 요청시 딸린 답변들도 함께 GET하기 위한 문제의식재고 및 요구사항

private List<Answer> sortBySortOption(long questionId, String sortOption) {
        if(sortOption.equals("newest")) {
            return answerRepository.findAllByQuestionId(questionId).
        }
        else if(sortOption.equals("oldest")) {
            return answerRepository.findAll(PageRequest.of(page, size, Sort.by("answerId").ascending()));
        }
        else if(sortOption.equals("score")) {
            return answerRepository.findAll(PageRequest.of(page, size, Sort.by("score").descending()));
        }
        return answerRepository.findAll(PageRequest.of(page, size, Sort.by("answerId").descending()));
        //정렬옵션을 선택하지 않았을때 기본 정렬 : 최신순
    }
  1. 1개의 질문에 딸린 모든 답변들을 끌어오는 것

//2. 그리고 그 답변들을 클라이언트의 옵션(최신순, 오래된 순)에 따라 정렬하는 것

  1. 마지막으로 QuestionAnswersResponseDto로 클라쪽에 돌려주는 것
    How? 아마도
    question :
    {"title" : "blabla",
    "body" : "blabla",
    "details" : "blabla"}, answers : [
    {answer1 :
    {bsgsdf : 13435, safdsgd : 5789},
    {answer2 : {asfgfh : 55555}
    ] pageinfo :
    {page : 1,
    size : 30,
    totalele :
    }

    RequestParam 즉 쿼리스트링을 귀찮게 쓰지 않기 위한 파라미터 값 설정

저렇게 required = false 설정해주면
쿼리스트링 안 써도 되겠지?


Question & Answer 각 엔티티에 score 필드는 별도의 테이블생성 필요함을 인식

@Column
private int score;

Answer 테이블엔티티에서 컬럼 삭제함

why? 마치 Member와 Stamp 처럼


내가 왜 UriCreator 공통클래스를 만들어 놓고도 Answer Post시에 쓰지 않고 수동으로 세팅한 이유

위 코드에서 URI location 줄을 보면 그냥 수동으로 넣는걸 볼 수 있다.
왜 그럴까?
밑 삽화에서 RequestMapping 엔드포인트를 보면 {id}이렇게
질문고유아이디를 패스파라미터로 세팅해놓은게 보일 것이다.

그런데 문제는 UriCreator 클래스에 있는 createUri()를 쓸 때
저 {id}가 바뀐다는 것이다. 그에 따라

IllegalArgumentException : Not enough variables available to expand 에러가 떠서 막혀버린다.

한번 구조를 보자

public class UriCreator {
    public static URI createUri(String defualtUrl, long resourceId) {
        return UriComponentsBuilder
                .newInstance()
                .path(defualtUrl + "/{resource-id}")
                .buildAndExpand(resourceId)
                .toUri();
    }
}

원래 resourceId는 로직흐름상 답변고유아이디가 반드시 들어가야 한다.
But 저 createUri()메소드를 이용하면
/api1/questions/{id}/answers/답변고유아이디
이렇게 구성해주는 것이 아니라

/api1/questions/resourceId/answers
이렇게 된다는 것이다.

따라서 아래처럼

수동으로 구성해야 내가 원하는 결과를 얻을 수 있다.


Answer테이블에 Question 외래키 채우기

먼저 AnswerController에서 DI로
쓰일 객체 끌어오기

그 다음 Answer 1개가 Post될때
연관된 상위의 1개 질문도 Answer테이블에 저장되도록 setter를 이용해주기


깃헙 사용법

git pull 하기 전에
먼저 local에서 작업한 내용들을 커밋 푸쉬하자!

깃 Conflicts 해결법 before 커밋


Auditable 관련해 EnableJpaAuditing 활성화

반드시 Auditable로 생성일 수정일 작성자등을 관리할 것이라면
메인 Spring Application클래스 위에
@EnableJpaAuditing을 꼭 붙여주자.

안 붙이고 그냥 Postman으로 요청을 보낸다면

..
..
blabla : {
	createdAt : null,
    modifiedAt : null
}

이렇게 뜨니까 OK?


가장 힘겨웠던 문제 : mapper 관련한 순환참조로 인해 질문 GET요청시 Postman 먹통

질문과 답변 각각 POST요청시엔 201 나오면서 잘 된다.
그러나 1개의 질문URL로 GET요청시 아래와 같이 뜬다.

또한 인텔리제이 콘솔창엔 아래와 같이 뜬다.

backend.com.backend.answer.entity.Answer["question"]->backend.com.backend.question.entity.Question["answers"]->org.hibernate.collection.internal.PersistentBag[0]->backend.com.backend.answer.entity.Answer["question"]->backend.com.backend.question.entity.Question["answers"]->org.hibernate.collection.internal.PersistentBag[0]->backend.com.backend.answer.entity.Answer["question"]->backend.com.backend.question.entity.Question["answers"]->org.hibernate.collection.internal.PersistentBag[0]->backend.com.backend.answer.entity.Answer["question"]->backend.com.backend.question.entity.Question["answers"])] with root cause

java.lang.StackOverflowError: null

저 길이 15배의 반복되는 에러가 intelliJ IDE에 뜨고 저렇게
스택오버플로우 에러가 뜬다. 왜 그럴까?

일단 질문1개에 딸린 답변들을 람다 스트림을 활용해서 참조하고 정렬하고
리턴하는 과정에서 여러가지 객체를 쓰게 된다.

(DI를 활용해서 객체.메소드())
그 과정에서 QuestionMapper의 객체와 AnswerMapper의 객체가
하나의 클래스 파일에 있을때 GET요청을 하면
순환참조(사실 왜 그런지는 정확히 모른다 ㅋㅋㅋ 그냥 원인에 따른 결과만 알 뿐 내부로직은 모른다)가 이루어져서 포스트맨에서 못 불러온다.

그래서 chatGPT씨에게 자문한 결과 해결했다. 아래는 그 내용이다.


두 가지 Mapper로 인한 순환참조 해결

chatGPT : The error message indicates that there is a circular reference in your data model that causes an infinite loop when serializing the object to JSON using Jackson. The stack trace shows that the circular reference is happening between the Question and Answer entities through the answers field of the Question entity.

To fix this issue, you can use the @JsonManagedReference and @JsonBackReference annotations provided by Jackson.

@JsonManagedReference is used to annotate the "forward" part of the relationship (i.e., the entity that manages the relationship), and @JsonBackReference is used to annotate the "back" part of the relationship (i.e., the entity that is pointed to by the forward part).

For example, in your Question entity, you can annotate the answers field with @JsonManagedReference("question-answers"):


따라서

이렇게 되었다. 아직 나아가야 할 사항은 많지만 첫 단추는 해결했다.
체감상 25%는 되지 않을까.
앞으로의 75%도 화이팅!!

profile
Flying books in the library are getting apart and then merging

0개의 댓글