ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 세상에 저녁부터 지금까지 붙잡고 늘어진 결과 이제 끝났구나.후..
징한 Spring 징한 Security 하지만 나의 훌륭한 상대가 되어 주었다.
결국엔 내가 이겼어. 난 더 강해졌어. 나에게 있어 이제 너희같은 문제들은 내가 좀 있음 완전히
지나칠 스테이지들 훗날엔 눈길조차 안 주고도 무심하게도 너희를 해결하고서는 마치
어라? 내가 낙엽을 밟고 지나갔나? 라고 느껴질만큼 성장해주마.
{
"id": 1,
"displayName": "나이수만",
"location": "서울",
"questions": [
{
"createdAt": "2023-04-26T10:17:55.039848",
"modifiedAt": "2023-04-26T10:17:55.039848",
"createdBy": "StackOverFlow",
"id": 1,
"title": "로켓로켓로켓단 피카피카피카츄",
"body": "내용물을 정했어!",
"writtenBy": "나이수만"
"answers" : [{"createdAt": "2023-04-26T10:18:06.476079",
"modifiedAt": "2023-04-26T10:18:06.476079",
"createdBy": "StackOverFlow",
"id": 1,
"content": "와츄워너두",
"writtenBy": "나이수만"
"comments" : [{"id" : 1,
"text" : "원하시는 내용을 입력했어요. 333"}]}]
}
],
"answers": [
{
"createdAt": "2023-04-26T10:18:06.476079",
"modifiedAt": "2023-04-26T10:18:06.476079",
"createdBy": "StackOverFlow",
"id": 1,
"content": "와츄워너두",
"writtenBy": "나이수만"
"comments" : [{"id" : 1,
"text" : "원하시는 내용을 입력했어요. 333"}]
}
],
"totalQuestions": 1,
"totalAnswers": 1
}
{
"id": 1,
"displayName": "나이수만",
"location": "서울",
"questions": [
{
"createdAt": "2023-04-26T10:17:55.039848",
"modifiedAt": "2023-04-26T10:17:55.039848",
"createdBy": "StackOverFlow",
"id": 1,
"title": "로켓로켓로켓단 피카피카피카츄",
"body": "내용물을 정했어!",
"writtenBy": "나이수만"
}
],
"answers": [
{
"createdAt": "2023-04-26T10:18:06.476079",
"modifiedAt": "2023-04-26T10:18:06.476079",
"createdBy": "StackOverFlow",
"id": 1,
"content": "와츄워너두",
"writtenBy": "나이수만"
}
],
"totalQuestions": 1,
"totalAnswers": 1
}
@JsonIgnoreProperties 이것을
엔티티의 필드가 아닌 ResponseDto에 있는 필드에 붙여야지 요청에 대한
응답이 해당 필드내부에 있는 속성들이 빠져서 저렇게 보이게 되는 것임
from Mr.Chat :
The error message you received indicates that there is a circular reference in the JSON data being returned. This means that there is a loop in the data structure that causes the serialization process to never complete, resulting in a stack overflow error.
To fix this issue, you need to break the circular reference in your data structure. One way to do this is by using Jackson's @JsonManagedReference and @JsonBackReference annotations to manage the serialization and deserialization of the data.
Here's an example of how to use these annotations:
In the Member class, we use @JsonManagedReference to indicate that the questions field should be serialized as part of the Member object. In the Question class, we use @JsonBackReference to indicate that the member field should be skipped during serialization, to avoid circular references.
With this configuration, when you serialize a Member object, the questions field will be included in the JSON output, but when you serialize a Question object, the member field will be skipped, and the circular reference will be avoided.
public Question createQuestion(Question question, UserDetails user) {
Optional<Member> member = memberRepository.findByEmail(user.getUsername());
Member findMember = member.orElseThrow(() -> new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND));
//question필드를 findMember를 통해 쌍방으로 세팅해준다.
findMember.setQuestion(question);
//Question 테이블에 있는 글쓴이 필드를 세팅해준다.
question.setWrittenBy(findMember.getDisplayName());
// memberRepository.save()를 하면 의존성에 의해 같은 내용의 엔티티가 두 번 등록되고 애꿎은
//PK만 올라간다. 그러니 밑에 코드 한번으로도 충분하다. 저러면
//Member 엔티티와 Answer엔티티 모두 영속성 컨텍스트에 저장되고 DB반영된다.
return questionRepository.save(question);
}
public Answer createAnswer(Answer answer, UserDetails user) {
Optional<Member> member = memberRepository.findByEmail(user.getUsername());
Member findMember = member.orElseThrow(() -> new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND));
//answer필드를 findMember를 통해 쌍방으로 세팅해준다.
findMember.setAnswer(answer);
//Answer 테이블에 있는 글쓴이 필드를 세팅해준다.
answer.setWrittenBy(findMember.getDisplayName());
// memberRepository.save()를 하면 의존성에 의해 같은 내용의 엔티티가 두 번 등록되고 애꿎은
//PK만 올라간다. 그러니 밑에 코드 한번으로도 충분하다. 저러면
//Member 엔티티와 Answer엔티티 모두 영속성 컨텍스트에 저장되고 DB반영된다.
return answerRepository.save(answer);
}
즉 애초에 Service 클래스에서 서로 다른 Repository 두 개를 동시에 DI받아서
memberRepository.save()
return question(or answer)Repository.save()
이게 뻘짓이었단 말이다. ㅋㅋㅋ
그러니 저 코드블럭으로 고쳐놓으니 중복등록 문제 해결됐다.
그래서 스택오버플로우 에러 났는데, 해결법을 알아냈지..
우선 Member 클래스는 MemberDetails가 상속하는 상위 클래스란 말이지.
근데. Comment 클래스 내부에서
public class Comment extends Auditable {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMBER_ID")
@JsonBackReference
private Member member;
}
이렇게 되어 있었단 말이야.
아마 인증정보로 활용하는 클래스를 필드로 받으면 결국 계층형 마지막 단계에 있는
클래스가 독박쓰고 UserDetails정보들과 Member의 모든필드 정보들이 막 넘어오면서
스택오버 에러나는듯해.. 그래서 결국은 그냥 Comment 내부에 @Column
private String writtenBy;만은 남겨놓고 저 member컬럼 삭제했더니
에러 안뜨고 이쁘게 잘 나옴
실습할때 만들었던 커피주문 애플리케이션의 경우 전체 커피 또는 전체 주문목록은 오직 Admin만이 인가를 받아서 엑세스할 수 있었다.
그러나 이번 스택오버플로우 클론어플에선 전체 질문이나 각 개인의
멤버프로필은 GET요청에 대한 엑세스가 가능하다.
즉 수정과 삭제 메서드에 관해서만 인가처리필터를 적용하면 되겠고
또한 질문과 답변 코멘트 POST 요청시
인증된 회원인지 먼저 확인하고 그 다음 해당요청에 대한 인가를 주는 것이 맞겠다.
이거 쓰면 테이블 안 만들어도 자동생성됨
그리고 신기한건 PK==FK로 쓰는 MEMBER_ROLES 테이블도 있음