- Comment 기능 만들어보기


댓글이 없다면 아직 작성된 댓글이 없습니다를 출력
이후 댓글이 달리는 경우 출력문이 사라지고 댓글을 출력
- Detail.jsp
먼저 댓글은 게시글을 들어가는 상세페이지에서 확인할 수 있기 때문에
Detail.jsp를 수정했습니다
추가로 사용된 CDN은 moment와 jquery입니다
moment - JavaScript로 작성된 날짜 및 시간 처리 라이브러리
날짜 및 시간을 쉽게 파싱, 조작, 표시할 수 있도록 다양한 기능을 제공
jquery - ajax용 그이상 이하도 아님
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
- Detail.jsp - body 추가
<tbody id="commentResult">
이렇게 table 태그 안에서도 구역을 head body foot으로 나누어주면
스타일을 넣어주기 훨씬 더 편합니다
<c:choose>
<c:when test="${cList == null}">
<tr>
<th colspan="6">
<h1>아직 작성된 댓글이 없습니다</h1>
</th>
</tr>
</c:when>
<c:otherwise>
<tr>
<th>id</th>
<th>작성자</th>
<th>내용</th>
<th>작성시간</th>
</tr>
<c:forEach items="${cList}" var="cList">
<tr>
<th>${cList.id}</th>
<th>${cList.commentWriter}</th>
<th>${cList.commentContents}</th>
<th>
<fmt:formatDate value="${cList.commentCreatedDate}"
pattern="yyyy-MM-dd HH:mm"></fmt:formatDate>
</th>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
여기까지가 게시글에 달린 댓글이 있는지 없는지를 DB에서 받아온
리스트의 값을 통해 판단하고 C태그의 조건문을 통해 결과를 출력합니다
여기서는 NULL일경우 댓글이 없다는 출력문이 출력되고,
NULL이 아니라면 받아온 값이 List이기 때문에 forEach문을 통해
반복문을 돌려 List를 출력해줍니다
</tbody>
<tfoot>
<tr>
<th colspan="6"><label for="commentWriter" style="float: left">작성자: </label>
<input type="text" name="commentWriter" id="commentWriter" style="float: left">
<label for="commentContents" style="margin-right: 187px">내용</label>
<input type="button" value="등록" style="float: right" onclick="helloComment(${boardDTO.id})">
</th>
</tr>
<tr>
<td colspan="6"><textarea id="commentContents" COLS="104" ROWS="5"></textarea></td>
</tr>
</tfoot>
foot 부분에서는 크게 신경쓸 부분이 없습니다
글작성 기능에서 textarea의 사이즈만 약간 변경후 이어 붙여준 모습입니다
전날까지 사용했던 Detail.jsp의 내용들은 thead로 테이블안에서 영역을 나눴습니다
오늘 수정한 내용은 tbody - 전체적인 댓글 출력 , tfoot - 댓글 입력으로 나눴습니다
- Detail.jsp - script
const helloComment = (id) => {
const commentWriter = document.getElementById('commentWriter').value;
const commentContents = document.getElementById('commentContents').value;
const boardId = id;
여기까지가 댓글을 서버에 저장해줄 정보들입니다
게시글의 id까지 함께 넘겨줘야 어떤 게시글에 달린 댓글인지 알아야하기 때문에
꼭 게시글의 id까지 함께 넘겨줘야합니다
const commentResult = document.getElementById('commentResult');
저희는 innerHTML을 사용해 값을 화면에 출력해줄것이기 때문에
새로 값을 넣어줄 부모태그의 객체변수가 필요합니다
$.ajax({
type: "post",
url: "/comment/save",
data: {
"commentWriter": commentWriter,
"commentContents": commentContents,
"boardId": boardId
},
위에서 객체변수로 받은 값들의 벨류를 DATA객체에 담아
URL에 파라미터 형식으로 넘겨줍니다
success: function (res) { 문제없이 작성 댓글을 DB에 넘겨준경우 실행!
let output = "<tr>";
output += "<th>id</th>";
output += "<th>작성자</th>";
output += "<th>내용</th>";
output += "<th>작성시간</th>";
output += "</tr>";
for (let i in res) {
output += "<tr>";
output += "<th>" + res[i].id + "</th>";
output += "<th>" + res[i].commentWriter + "</th>";
output += "<th>" + res[i].commentContents + "</th>";
output += "<th>" + moment(res[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss") + "</th>";
output += "</tr>";
}
댓글이 보이는 공간을 새로 덮어씌워 표현하였습니다
List로 전에 있던 댓글과 지금 작성한 댓글을 모두 가져왔기 때문에
output이라는 let변수를 만들고 table태그의 양식에 맞게 문자열을 만들 담아줍니다
당연히 List로 받아온 값은 for문을 돌려 문자열에 추가로 저장해줍니다
commentResult.innerHTML = output;
이후 이렇게 output에 저장된 문자열을 commentResult에 덮어씌워주면
화면은 비동기형식으로 수정출력됩니다
document.getElementById('commentWriter').value = "";
document.getElementById('commentContents').value = "";
이후 댓글을 달기위해 작성했던 작성자와 댓글공간을 지워주며 마무리합니다
},
error: function () { 실행에 문제가 있다면 실행 ㅠㅠ
console.log("실패");
}
})
}
댓글을 달면 바로 화면에 표현하기 위해 비동기로 작동하는 ajax를 사용하였습니다
ajax를 사용하여 스타일을 쉽게주기 위해 table을 3개구분 head / body / foot로 나누었습니다
- CommentDTO - 참고용
@Data
@NoArgsConstructor
public class CommentDTO {
Long id;
String commentWriter;
String commentContents;
Long boardId;
Timestamp commentCreatedDate;
}
- Controller - GetMapping
@GetMapping
public String boardDetail(@RequestParam("id") Long id , Model model){
boardService.updateHits(id);
BoardDTO boardDTO = boardService.boardDetail(id);
if(boardDTO.getFileAttached() == 1){
List<BoardFileDTO> boardFileList = boardService.findFile(id);
model.addAttribute("boardFileList",boardFileList);
System.out.println("boardFileDTO = " + boardFileList);
}
여기까지는 전까지의 GetMpping과 다르지 않습니다
List<CommentDTO> cList = commentService.boardComment(id);
if(cList.size()==0){
model.addAttribute("cList",null);
}else{
model.addAttribute("cList",cList);
}
DB에서 List정보를 받아오고 List의 사이즈에 따라 model에 담기는 값이
null일지 List일지를 결정해줍니다
위의 jsp를 보면 null이라면 댓글없음 , null이 아니라면 댓글을 출력합니다
model.addAttribute("boardDTO",boardDTO);
return "boardPages/boardDetail";
}
- Controller - PostMapping
@PostMapping("/comment/save")
public ResponseEntity commentSave(@ModelAttribute CommentDTO commentDTO){
ResponseEntity를 사용하였고 파라미터로 받은 정보를
ModelAttribute로 바로 객체에 저장하였습니다
commentService.save(commentDTO);
이후 받은 객체를 service로 넘겨주었습니다
List<CommentDTO> commentDTOList = commentService.boardComment(commentDTO.getBoardId());
넘겨준 객체 정보를 저장후 전에 있을지 모르는 댓글과 함께 List로 저장하여
넘겨받았습니다
return new ResponseEntity<>(commentDTOList,HttpStatus.OK);
이렇게 commentDTOList를 넘겨받았다면 OK로 잘실행됩니다
}
- Service
public List<CommentDTO> boardComment(Long id) {
return commentRepository.boardComment(id);
}
처음 detail에 들어왔을때 , 댓글을 새로 작성했을때 사용됩니다
public void save(CommentDTO commentDTO) {
commentRepository.save(commentDTO);
}
새로운 댓글을 저장할때 사용됩니다
- Repository
public List<CommentDTO> boardComment(Long id) {
return sql.selectList("Board.boardComment",id);
}
Detail에 들어가거나 새로 댓글을 작성했을때 사용됩니다
public void save(CommentDTO commentDTO) {
sql.insert("Board.commentSave",commentDTO);
}
새로운 댓글을 저장할때 사용됩니다
- Mapper
<select id="boardComment" parameterType="Long" resultType="comment">
select * from comment_table where boardId = #{id} order by id asc
</select>
요청받은 정보의 ID값을 토대로 검색하여 List에 댓글번호 오름차순으로 담아 값을 넘겨줍니다
<insert id="commentSave" parameterType="comment">
insert into comment_table(commentWriter,commentContents,boardId)
values (#{commentWriter},#{commentContents},#{boardId})
</insert>
Mysql 문법에 맞게 Mapper를 통해 DB에 저장해줍니다
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 54일차 -비로그인 게시판- 검색 / 검색결과 페이징 (0) | 2023.05.10 |
---|---|
인천 일보 아카데미 53일차 -비로그인 게시판- List 페이징 기능 (0) | 2023.05.09 |
인천 일보 아카데미 52일차 -1- 이미지 업로드 / detail에 이미지 보여주기 (0) | 2023.05.07 |
인천 일보 아카데미 51일차 -1- 비로그인 게시판 만들어보기 (0) | 2023.05.07 |
인천 일보 아카데미 50일차 -2- Email - 중복체크 (개인저장 내용X) (0) | 2023.05.02 |
- Comment 기능 만들어보기


댓글이 없다면 아직 작성된 댓글이 없습니다를 출력
이후 댓글이 달리는 경우 출력문이 사라지고 댓글을 출력
- Detail.jsp
먼저 댓글은 게시글을 들어가는 상세페이지에서 확인할 수 있기 때문에
Detail.jsp를 수정했습니다
추가로 사용된 CDN은 moment와 jquery입니다
moment - JavaScript로 작성된 날짜 및 시간 처리 라이브러리
날짜 및 시간을 쉽게 파싱, 조작, 표시할 수 있도록 다양한 기능을 제공
jquery - ajax용 그이상 이하도 아님
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
- Detail.jsp - body 추가
<tbody id="commentResult">
이렇게 table 태그 안에서도 구역을 head body foot으로 나누어주면
스타일을 넣어주기 훨씬 더 편합니다
<c:choose>
<c:when test="${cList == null}">
<tr>
<th colspan="6">
<h1>아직 작성된 댓글이 없습니다</h1>
</th>
</tr>
</c:when>
<c:otherwise>
<tr>
<th>id</th>
<th>작성자</th>
<th>내용</th>
<th>작성시간</th>
</tr>
<c:forEach items="${cList}" var="cList">
<tr>
<th>${cList.id}</th>
<th>${cList.commentWriter}</th>
<th>${cList.commentContents}</th>
<th>
<fmt:formatDate value="${cList.commentCreatedDate}"
pattern="yyyy-MM-dd HH:mm"></fmt:formatDate>
</th>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
여기까지가 게시글에 달린 댓글이 있는지 없는지를 DB에서 받아온
리스트의 값을 통해 판단하고 C태그의 조건문을 통해 결과를 출력합니다
여기서는 NULL일경우 댓글이 없다는 출력문이 출력되고,
NULL이 아니라면 받아온 값이 List이기 때문에 forEach문을 통해
반복문을 돌려 List를 출력해줍니다
</tbody>
<tfoot>
<tr>
<th colspan="6"><label for="commentWriter" style="float: left">작성자: </label>
<input type="text" name="commentWriter" id="commentWriter" style="float: left">
<label for="commentContents" style="margin-right: 187px">내용</label>
<input type="button" value="등록" style="float: right" onclick="helloComment(${boardDTO.id})">
</th>
</tr>
<tr>
<td colspan="6"><textarea id="commentContents" COLS="104" ROWS="5"></textarea></td>
</tr>
</tfoot>
foot 부분에서는 크게 신경쓸 부분이 없습니다
글작성 기능에서 textarea의 사이즈만 약간 변경후 이어 붙여준 모습입니다
전날까지 사용했던 Detail.jsp의 내용들은 thead로 테이블안에서 영역을 나눴습니다
오늘 수정한 내용은 tbody - 전체적인 댓글 출력 , tfoot - 댓글 입력으로 나눴습니다
- Detail.jsp - script
const helloComment = (id) => {
const commentWriter = document.getElementById('commentWriter').value;
const commentContents = document.getElementById('commentContents').value;
const boardId = id;
여기까지가 댓글을 서버에 저장해줄 정보들입니다
게시글의 id까지 함께 넘겨줘야 어떤 게시글에 달린 댓글인지 알아야하기 때문에
꼭 게시글의 id까지 함께 넘겨줘야합니다
const commentResult = document.getElementById('commentResult');
저희는 innerHTML을 사용해 값을 화면에 출력해줄것이기 때문에
새로 값을 넣어줄 부모태그의 객체변수가 필요합니다
$.ajax({
type: "post",
url: "/comment/save",
data: {
"commentWriter": commentWriter,
"commentContents": commentContents,
"boardId": boardId
},
위에서 객체변수로 받은 값들의 벨류를 DATA객체에 담아
URL에 파라미터 형식으로 넘겨줍니다
success: function (res) { 문제없이 작성 댓글을 DB에 넘겨준경우 실행!
let output = "<tr>";
output += "<th>id</th>";
output += "<th>작성자</th>";
output += "<th>내용</th>";
output += "<th>작성시간</th>";
output += "</tr>";
for (let i in res) {
output += "<tr>";
output += "<th>" + res[i].id + "</th>";
output += "<th>" + res[i].commentWriter + "</th>";
output += "<th>" + res[i].commentContents + "</th>";
output += "<th>" + moment(res[i].commentCreatedDate).format("YYYY-MM-DD HH:mm:ss") + "</th>";
output += "</tr>";
}
댓글이 보이는 공간을 새로 덮어씌워 표현하였습니다
List로 전에 있던 댓글과 지금 작성한 댓글을 모두 가져왔기 때문에
output이라는 let변수를 만들고 table태그의 양식에 맞게 문자열을 만들 담아줍니다
당연히 List로 받아온 값은 for문을 돌려 문자열에 추가로 저장해줍니다
commentResult.innerHTML = output;
이후 이렇게 output에 저장된 문자열을 commentResult에 덮어씌워주면
화면은 비동기형식으로 수정출력됩니다
document.getElementById('commentWriter').value = "";
document.getElementById('commentContents').value = "";
이후 댓글을 달기위해 작성했던 작성자와 댓글공간을 지워주며 마무리합니다
},
error: function () { 실행에 문제가 있다면 실행 ㅠㅠ
console.log("실패");
}
})
}
댓글을 달면 바로 화면에 표현하기 위해 비동기로 작동하는 ajax를 사용하였습니다
ajax를 사용하여 스타일을 쉽게주기 위해 table을 3개구분 head / body / foot로 나누었습니다
- CommentDTO - 참고용
@Data
@NoArgsConstructor
public class CommentDTO {
Long id;
String commentWriter;
String commentContents;
Long boardId;
Timestamp commentCreatedDate;
}
- Controller - GetMapping
@GetMapping
public String boardDetail(@RequestParam("id") Long id , Model model){
boardService.updateHits(id);
BoardDTO boardDTO = boardService.boardDetail(id);
if(boardDTO.getFileAttached() == 1){
List<BoardFileDTO> boardFileList = boardService.findFile(id);
model.addAttribute("boardFileList",boardFileList);
System.out.println("boardFileDTO = " + boardFileList);
}
여기까지는 전까지의 GetMpping과 다르지 않습니다
List<CommentDTO> cList = commentService.boardComment(id);
if(cList.size()==0){
model.addAttribute("cList",null);
}else{
model.addAttribute("cList",cList);
}
DB에서 List정보를 받아오고 List의 사이즈에 따라 model에 담기는 값이
null일지 List일지를 결정해줍니다
위의 jsp를 보면 null이라면 댓글없음 , null이 아니라면 댓글을 출력합니다
model.addAttribute("boardDTO",boardDTO);
return "boardPages/boardDetail";
}
- Controller - PostMapping
@PostMapping("/comment/save")
public ResponseEntity commentSave(@ModelAttribute CommentDTO commentDTO){
ResponseEntity를 사용하였고 파라미터로 받은 정보를
ModelAttribute로 바로 객체에 저장하였습니다
commentService.save(commentDTO);
이후 받은 객체를 service로 넘겨주었습니다
List<CommentDTO> commentDTOList = commentService.boardComment(commentDTO.getBoardId());
넘겨준 객체 정보를 저장후 전에 있을지 모르는 댓글과 함께 List로 저장하여
넘겨받았습니다
return new ResponseEntity<>(commentDTOList,HttpStatus.OK);
이렇게 commentDTOList를 넘겨받았다면 OK로 잘실행됩니다
}
- Service
public List<CommentDTO> boardComment(Long id) {
return commentRepository.boardComment(id);
}
처음 detail에 들어왔을때 , 댓글을 새로 작성했을때 사용됩니다
public void save(CommentDTO commentDTO) {
commentRepository.save(commentDTO);
}
새로운 댓글을 저장할때 사용됩니다
- Repository
public List<CommentDTO> boardComment(Long id) {
return sql.selectList("Board.boardComment",id);
}
Detail에 들어가거나 새로 댓글을 작성했을때 사용됩니다
public void save(CommentDTO commentDTO) {
sql.insert("Board.commentSave",commentDTO);
}
새로운 댓글을 저장할때 사용됩니다
- Mapper
<select id="boardComment" parameterType="Long" resultType="comment">
select * from comment_table where boardId = #{id} order by id asc
</select>
요청받은 정보의 ID값을 토대로 검색하여 List에 댓글번호 오름차순으로 담아 값을 넘겨줍니다
<insert id="commentSave" parameterType="comment">
insert into comment_table(commentWriter,commentContents,boardId)
values (#{commentWriter},#{commentContents},#{boardId})
</insert>
Mysql 문법에 맞게 Mapper를 통해 DB에 저장해줍니다
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 54일차 -비로그인 게시판- 검색 / 검색결과 페이징 (0) | 2023.05.10 |
---|---|
인천 일보 아카데미 53일차 -비로그인 게시판- List 페이징 기능 (0) | 2023.05.09 |
인천 일보 아카데미 52일차 -1- 이미지 업로드 / detail에 이미지 보여주기 (0) | 2023.05.07 |
인천 일보 아카데미 51일차 -1- 비로그인 게시판 만들어보기 (0) | 2023.05.07 |
인천 일보 아카데미 50일차 -2- Email - 중복체크 (개인저장 내용X) (0) | 2023.05.02 |