게시글 댓글 만들기
[details.jsp]
<!-- 게시글 댓글 -->
<div class="card">
<div class="card-body"><textarea class="form-control" rows="1" ></textarea></div>
<div class="card-footer"><button class="btn btn-primary">등록</button></div>
</div>
<div class="card">
<div class="card-header">댓글 리스트</div>
<ul id="reply--box" class="list-group">
<li id="reply--1" class="list-group-item d-flex justify-content-between">
<div>댓글 내용!</div>
<div class="d-flex">
<div class="font-italic">작성자 : user </div>
<button class="badge">삭제</button>
</div>
</li>
</ul>
</div>
-   : 한 칸 띄어쓰기, 공백을 의미하는 특수문자
- class="badge" : 크기를 작게 만듬
테스트로 DB에 직접 댓글 넣기
insert into reply(content, boardId, userId, createDate)
values('첫번재 댓글',15,2,now());
insert into reply(content, boardId, userId, createDate)
values('두번재 댓글',15,2,now());
insert into reply(content, boardId, userId, createDate)
values('세번재 댓글',15,2,now());
commit;
게시글 상세보기를 클릭했을때 댓글이 보이는거라서 BoardService 에서 처리하는데
findById 해서 Board 를 들고 BoardController 에서 받는다
1.
[BoardService]
@Transactional(readOnly = true)
public Board 글상세보기(int id){
return boardRepository.findById(id)
.orElseThrow(()->{
return new IllegalArgumentException("글 상세보기 실패 : 아이디를 찾을 수 없습니다.");
});
}
2.
ReplyRepository 인터페이스 생성하기
public interface ReplyRepository extends JpaRepository<Reply, Integer>{ // Reply 의 id가 int니까 Integer
}
3.
[BoardController]
@GetMapping("/board/{id}")
public String findById(@PathVariable int id, Model model) {
model.addAttribute("board",boardService.글상세보기(id));
return "board/detail";
}
boardService.글상세보기(id) ▶ BoardService에서 findById 한 Board 를 들고 BoardController 에 받는다.
Board 객체에는 reply를 들고있어서 뷰페이지(board/detail)로 리턴될때 reply를 반복문으로 forEach 해서 들고온다.
↓
[board]
reply 를 EAGER전략으로 패치해서 들고옴
@OneToMany(mappedBy = "board",fetch = FetchType.EAGER)
@JsonIgnoreProperties({"board"})
private List<Reply> replys;
[details.jsp]
* model.addAttribute("board",boardService.글상세보기(id));
<!-- 게시글 댓글 -->
<div class="card">
<div class="card-body"><textarea class="form-control" rows="1" ></textarea></div>
<div class="card-footer"><button class="btn btn-primary">등록</button></div>
</div>
<div class="card">
<div class="card-header">댓글 리스트</div>
<ul id="reply--box" class="list-group">
<c:forEach var="reply" items="${board.replys}">
<li id="reply--1" class="list-group-item d-flex justify-content-between">
<div>${reply.content}</div>
<div class="d-flex">
<div class="font-italic">작성자 : ${reply.user.username} </div>
<button class="badge">삭제</button>
</div>
</li>
</c:forEach>
</ul>
</div>
작성자는 ${reply.user.username}
Reply 객체 안에 ▶ User 객체 ▶ User 객체 안에 username
댓글들이 forEach문으로 나온다
하지만 여기까지는 문제가 없을지라도 나중에 무한참조의 문제가 생긴다.
위처럼 board 객체를 select하면 board 객체에 reply, user 가 포함돼 있으니 자동으로 가져오고
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob // 대용량 데이터
private String content; // 섬머노트 라이브러리 <html>태그가 섞여서 디자인이 됨.
private int count; // 조회수
@ManyToOne(fetch = FetchType.EAGER) // Many = Many, User = One
@JoinColumn(name="userId")
private User user; // DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE) // mappedBy 연관관계의 주인이 아니다 (난 FK가 아니에요) DB에 칼럼을 만들지 마세요.
@JsonIgnoreProperties({"board"})
@OrderBy("id desc")
private List<Reply> replys;
@CreationTimestamp
private LocalDateTime createDate;
}
가져온 reply 객체에는 board, user 가 있어서 또 중복되게 들고오는 무한참조의 문제가 생긴다
public class Reply {
@Id //Primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // 프로젝트에서 연결된 DB의 넘버링 전략을 따라간다.
private int id; // 시퀀스, auto_increment
@Column(nullable = false, length = 200)
private String content;
@ManyToOne
@JoinColumn(name="boardId")
private Board board;
@ManyToOne
@JoinColumn(name="userId")
private User user;
@CreationTimestamp
private LocalDateTime createDate;
@Override
public String toString() {
return "Reply [id=" + id + ", content=" + content + ", board=" + board + ", user=" + user + ", createDate="
+ createDate + "]";
}
}
에러 StackOverflowError
해결
오류메세지를 자세히 보니 @Data를 가르키고 있어서
Board, User 엔티티에서 @Data 빼고 @Getter, @Setter 를 추가를 했더니 해결되었다.
언제 문제가 되는지 무한참조 테스트하기
[ReplyControllerTest]
@RestController
public class ReplyControllerTest {
@Autowired
private BoardRepository boardRepository;
@GetMapping("/test/board/{id}")
public Board getBord(@PathVariable int id) {
return boardRepository.findById(id).get();
}
}
- 결과
리턴을 하면 무한참조가 되어버림.
* http://localhost:8000/test/board/15
이유는??
리턴할때 jackson 라이브러리가 발동하는데
( jackson 라이브러리가 발동한다는 것은 오브젝트를 json으로 리턴해준다는 말 )
그때 모델이 들고있는 getter를 호출하고 값들을 json으로 바꾼다.
@GetMapping("/test/board/{id}")
public Board getBord(@PathVariable int id) {
return boardRepository.findById(id).get();
}
Board 객체가 실행되는거니까
Board 오브젝트 안에 있는
▷ getId, getTitle, getContent, getCount, getUser, getReply, getCreateDate 가 호출된다
getUser 를 호출하면 User 오브젝트가 실행.
▷ getId, getPassword, getEmail, getRole, getOauth, getCreateDate
= User는 연관관계가 없어서 깔끔하게 들고온다.
getReply 를 호출하면 Reply 오브젝트가 실행.
▷ getId, getContent, getBoard, getUser, getCreateDate
이때 다시 getBoard를 리턴하니까 또 Board 객체가 실행된다!
그럼 또다시 Board ▷ getId, getTitle, getContent, getCount, getUser, getReply, getCreateDate 리턴.
다시 Reply ▷ getId, getContent, getBoard, getUser, getCreateDa 호출... 이렇게 무한참조가 된다.
다음 글에 무한참조 해결법..
'Spring boot | 블로그 만들기' 카테고리의 다른 글
블로그 만들기 | 게시글 댓글 작성, 댓글 삭제 (0) | 2022.11.25 |
---|---|
블로그 만들기 | 무한참조 해결법 2가지 @JsonIgnoreProperties , 객체 다이렉트 호출 (0) | 2022.11.24 |
블로그 만들기 | [카카오API] 카카오 로그인시 회원통합 (1) (1) | 2022.11.19 |
블로그 만들기 | [카카오API] 사용자 정보 요청하기(4) (0) | 2022.11.18 |
블로그 만들기 | [카카오API] .getBody() , ObjectMapper 라이브러리(3) (1) | 2022.11.18 |