처음에 댓글을 만들 때에는 게시판 테이블을 먼저 불러오고 댓글 테이블을 불러오는 형식이 됐었는데
이렇게 된 이유가 댓글 테이블에만 게시판 테이블의 연관관계를 걸어(단방향) 게시판 테이블을 조회했을 때 댓글 테이블이 같이
조회가 될 수 없는 구조 였다. 이렇게 만들게 되면 굉장히 비효율적일 것 같았다..
그래서 게시판 테이블에 댓글 테이블의 연관관계 @OneToMany를 같이 걸어줘서 양방향으로 만든 후 게시판 테이블을 조회했을 때
댓글까지 불러올 수 있었다.
- thymeleaf (board.html)
- Controller
/**
* 타임 리프 게시판 상세내용 화면
* @param model
* @param board_id
* @return
*/
@GetMapping("/thymeleaf/get_board")
public String getBoard(
Model model,
@RequestParam("board_id") Long board_id) {
OneBoardResponseDTO oneBoard = boardService.getOneBoard(board_id);
model.addAttribute("board", oneBoard);
return "boardDetail";
}
boardDetail.html의 글번호 1을 눌렀을 때 매핑되는 컨트롤러 함수이다.
- BoardServiceImpl
/**
* 게시판 상세내용 응답함수
* @param board_id
* @return
*/
@Override
public OneBoardResponseDTO getOneBoard(Long board_id) {
Optional<BoardEntity> boardEntity = boardRepository.findById(board_id);
List<CommentResponseDTO> commentResponseDTOList = new ArrayList<>();
OneBoardResponseDTO oneBoardResponseDTO = OneBoardResponseDTO.builder()
.board_id(boardEntity.get().getId())
.title(boardEntity.get().getTitle())
.content(boardEntity.get().getContent())
.writer(boardEntity.get().getUserInfoEntity().getNickname())
.createdDate(boardEntity.get().getCreatedDate())
.viewCnt(boardEntity.get().getViewCnt())
.build();
for(int i=0;i<boardEntity.get().getCommentEntity().size();i++){
CommentResponseDTO individualCommentResponse = CommentResponseDTO.builder()
.comment(boardEntity.get().getCommentEntity().get(i).getComment())
.writer(boardEntity.get().getCommentEntity().get(i).getWriter())
.createdDate(boardEntity.get().getCommentEntity().get(i).getCreatedDate())
.build();
commentResponseDTOList.add(individualCommentResponse);
System.out.println("개별적인 코멘트 Response"+individualCommentResponse.getComment());
}
oneBoardResponseDTO.setCommentResponseDTOList(commentResponseDTOList);
return oneBoardResponseDTO;
}
서비스를 보면 게시판 Repository를 통해 한번만 boardEntity를 호출하는데 유저정보와 코멘트를 같이 찾아올 수 있다
이렇게 되는 이유는 아래와 같이 boradEntity에 연관관계를 걸어줘서 가능한 것이다.
- boardEntity
@Entity
@RequiredArgsConstructor
@Getter
public class BoardEntity extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@ManyToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private UserInfoEntity userInfoEntity;
@OneToMany(mappedBy = "boardEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<CommentEntity> commentEntity;
@Column(nullable = false)
private String content;
@Column(nullable = false)
private int viewCnt;
@Builder
public BoardEntity(Long id, String title, UserInfoEntity userInfoEntity, List<CommentEntity> commentEntity, String content, int viewCnt) {
this.id = id;
this.title = title;
this.userInfoEntity = userInfoEntity;
this.commentEntity = commentEntity;
this.content = content;
this.viewCnt = viewCnt;
}
}
하나의 게시글에 댓글은 여러개가 생길 수 있으므로 댓글 연관 관계의 변수는 List 또는 Set으로 해줘야 될 것 같다.
- CommentEntity
@Entity
@Getter
@RequiredArgsConstructor
public class CommentEntity extends BaseTimeEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String writer;
@Column(nullable = false)
private String comment;
@JsonBackReference
@ManyToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private BoardEntity boardEntity;
@Builder
public CommentEntity(Long id, String writer, String comment, BoardEntity boardEntity) {
this.id = id;
this.writer = writer;
this.comment = comment;
this.boardEntity = boardEntity;
}
}
BoardEntity의 연관관계에 @JsonBackRefernce를 달아준 이유는 위의 BoardServiceImpl에서 게시글을 JPA로 findby를 하게 되면 연관관계까지 전부 다 select를 하게 된다고 했는데 그 과정에서 연관관계의 연관관계 테이블도 호출하게 된다. 그렇게 되면 BoardEntity는 CommentEntity를 호출하게 되고 CommentEntity는 BoardEntity를 연관관계로 가지고 있으니까 다시 BoardEntity를 호출하게되어 오버플로우로 무한 순환참조가 되기때문에 이 현상을 막기 위해 필요한 어노테이션이다.
- boardDetail.html (thymeleaf)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>BoardDetail</title>
</head>
<body>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script>
const map = {
team_id: null,
comment: null
}
function requestComment() {
map.comment = document.getElementById('comment').value;
map.team_id = document.getElementById('team_id').value;
console.log(map.comment);
console.log(map.team_id);
$.ajax({
contentType : "application/json",
url: "/thymeleaf/create/comment",
type: "POST",
dataType: JSON,
data: JSON.stringify(map),
xhrFields: {
withCredentials: true
}
}).done(function (res) {
console.log(res);
});
}
</script>
<h2 th:text="${board.title}"></h2>
<strong>작성자 : </strong>
<span th:text="${board.getWriter()}"></span>
<hr/>
<strong>생성 날짜 : </strong>
<span th:text="${board.getCreatedDate()}"></span>
<hr/>
<strong>조회 수 : </strong>
<span th:text="${board.getViewCnt()}"></span>
<hr/>
<strong>내용 : </strong>
<span th:text="${board.getContent()}"></span>
<hr/>
<h3>댓글</h3>
<table>
<tr>
<th>작성자</th>
<th>내용</th>
<th>생성 날짜</th>
</tr>
<tr th:each="commentList : ${board.getCommentResponseDTOList()}">
<td th:text="${commentList.getWriter()}"></td>
<td th:text="${commentList.getComment()}"></td>
<td th:text="${commentList.getCreatedDate()}"></td>
</form>
</tr>
</table>
<p></p>
<input id="team_id" type="hidden" th:value="${board.getBoard_id()}">
<input placeholder="댓글 작성" id="comment">
<input type="button" value="입력" onclick="requestComment()">
</body>
</html>
<script>의 ajax는 댓글 생성 요청 api이다.
'JAVA' 카테고리의 다른 글
Spring Boot 회원정보 출력 (1) 비동기 통신 Ajax (0) | 2022.09.15 |
---|---|
SpringBoot thymeleaf Ajax 비통기 통신 parsererror 이슈 해결 (0) | 2022.09.08 |
Spring Boot, thymeleaf ajax로그인 요청 (javascript) (0) | 2022.09.03 |
Spring Boot 게시판 상세내용 조회 구현 (0) | 2022.08.31 |
Spring Boot 전체 게시판 정렬 및 Pageable (paging) (0) | 2022.08.31 |
댓글