고래씌
[Spring] 9. 댓글 목록, 등록, 수정, 삭제(비동기식) 본문
1. 댓글 목록
=> 다음과 같이 파일 모두 생성
▶ Reply.vo
package com.kh.spring.board.model.vo;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@NoArgsConstructor
@ToString
public class Reply {
private int replyNo;
private String replyContent;
private String refBno;
private String replyWriter;
private String createDate;
private String status;
}
▶ ReplyController.java
@RestController |
Rest(Representaional state Transfer) : 자원을 url 이름으로 구분하여 자원의 상태(state)를 주고받는것(transfer)
=> @ResponseBody + @Controller : 요청에 따른 응답데이터가 모두 값(JSON) 그 자체인 컨트롤러
=> 비동기방식으로 통신하는 메소드들로만 몸통이 구현되어 있음
package com.kh.spring.board.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.kh.spring.board.model.service.ReplyService;
import com.kh.spring.board.model.vo.Reply;
@RestController
@RequestMapping("/reply")
public class ReplyController {
@Autowired
private ReplyService service;
// 댓글목록 조회(select) 서비스 → GET
@GetMapping("/selectReplyList")
public List<Reply> selectReplyList(int boardNo) {
List<Reply> rList = service.selectReplyList(boardNo); // 알아서 JSON 형태로 반환해줌
return rList;
}
}
▶ ReplyService.java
package com.kh.spring.board.model.service;
import java.util.List;
import com.kh.spring.board.model.vo.Reply;
public interface ReplyService {
// 댓글 목록 조회
List<Reply> selectReplyList(int boardNo);
}
▶ ReplyServiceImpl.java
package com.kh.spring.board.model.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.kh.spring.board.model.dao.ReplyDao;
import com.kh.spring.board.model.vo.Reply;
@Service
public class ReplyServiceImpl implements ReplyService{
@Autowired
private ReplyDao replyDao;
@Override
public List<Reply> selectReplyList(int boardNo) {
return replyDao.selectReplyList(boardNo);
}
}
▶ ReplyDao.java
package com.kh.spring.board.model.dao;
import java.util.List;
import com.kh.spring.board.model.vo.Reply;
public interface ReplyDao {
// 댓글 목록 조회
List<Reply> selectReplyList(int boardNo);
}
▶ ReplyDaoImpl.java
package com.kh.spring.board.model.dao;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.kh.spring.board.model.vo.Reply;
@Repository
public class ReplyDaoImpl implements ReplyDao{
@Autowired
private SqlSessionTemplate sqlSession;
// 댓글목록 조회
@Override
public List<Reply> selectReplyList(int boardNo) {
return sqlSession.selectList("replyMapper.selectReplyList", boardNo);
}
}
▶ reply-mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="replyMapper">
<select id="selectReplyList" parameterType="int" resultType="reply">
SELECT
REPLY_NO,
REPLY_CONTENT,
REF_BNO,
USER_NAME AS REPLY_WRITER,
CREATE_DATE,
REPLY.STATUS
FROM REPLY
LEFT JOIN MEMBER ON REPLY_WRITER = USER_NO
WHERE REF_BNO = #{boardNo} AND REPLY.STATUS = 'Y'
</select>
</mapper>
▶ boardDetailView.jsp
맨아래에 아래 코드 ajax 코드 추가
<script>
// 댓글목록 비동기 조회
function selectReplyList(){
$.ajax({
url : "${contextPath}/reply/selectReplyList",
data : {
boardNo : '${boardNo}'
},
success : function(result){ // result → List<Reply> → [ {댓글}, {댓글} ]
let replys = "";
for(let reply of result){
replys += "<tr>";
replys += "<td>"+ reply.replyWriter +"</td>";
replys += "<td>"+ reply.replyContent +"</td>";
replys += "<td>"+ reply.createDate +"</td>";
replys += "</tr>";
}
$("#replyArea tbody").html(replys); // 문자열로 된 tr태그들을 다 넣어줌
$("#rcount").html(result.length); // 댓글 총 개수
}
})
}
selectReplyList(); // 이 페이지에 접근했을 때 이 함수가 호출되도록 설정
</script>
▶ 결과
2. 댓글 등록
▶ boardDetailView.jsp
// 댓글 추가
function insertReply(){
// Reply에 한행의 데이터를 기록
$.ajax({
url : '${contextPath}/reply/insertReply',
data : { // 백엔드서버에서 커맨드객체형태로 데이터를 얻어오기 위해서 Reply.vo에 객체이름을 똑같이 지정한다.
refBno : '${boardNo}'
replyWriter : '${loginUser.userNo}',
replyContent : $("#replyContent").val()
},
type : 'POST',
success : function(result){
if(result == 0){
alert("댓글등록실패")
}else{
alert("댓글등록성공")
}
selectReplyList(); // 댓글 목록 불러오는 함수
$("#replyContent").val("");
}
})
}
▶ ReplyController.java
// 댓글 등록
@PostMapping("/insertReply")
public int insertReply(Reply r) {
return service.insertReply(r);
}
▶ ReplyService.java
int insertReply(Reply r);
▶ ReplyServiceImpl.java
@Override
public int insertReply(Reply r) {
return replyDao.insertReply(r);
}
▶ ReplyDao.java
int insertReply(Reply r);
▶ ReplyDaoImpl.java
@Override
public int insertReply(Reply r) {
return sqlSession.insert("replyMapper.insertReply",r);
}
▶ reply-mapper.xml
<!-- 댓글 등록 -->
<!-- replyContent는 XSS 공격을 받기 되게 좋음 -->
<insert id="insertReply" parameterType='reply'>
INSERT INTO REPLY
VALUES(SEQ_RNO.NEXTVAL, #{replyContent}, #{refBno}, #{replyWriter}, DEFAULT, DEFAULT)
</insert>
3. 댓글 수정
mybatis를 사용할 때, parameterMap 및 parameterType, resultMap 및 resultType을 선언하여 사용한다.
간단하게 정리하면 다음과 같이 정리할 수 있다.
- parameterMap : 비즈니스 로직으로부터 전달 받은, SQL 구문에 사용될 매개변수를 담은 객체
- parameterType : 비즈니스 로직으로부터 전달 받은, SQL 구문에 사용될 매개변수의 자료형
- resultMap : 비즈니스 로직으로 반환할, 결과값을 담은 객체
- resultType : 비즈니스 로직으로 반환할, 결과값의 자료형
▶ boardDetailView.jsp
=> 댓글 목록을 불려왔었던 코드에서 수정/삭제할 수 있도록 버튼 추가
function showReplyUpdateForm(replyNo, btn){
// 1. 댓글을 수정할 수 있는 textArea 생성
const textarea = document.createElement("textarea"); // 수정하기 폼
const button = document.createElement("button"); // 수정버튼
button.innerText = "수정";
// 버튼요소기준 부모요소(td)의 부모요소(tr)의 자식들([td, td, td]을 1번 인덱스에 있는 자식.(댓글내용 td))
let td = btn.parentElement.parentElement.children[1]; // 댓글내용이 있는 td태그
textarea.innerHTML = td.innerHTML; // 댓글내용복사
td.innerHTML = "";
td.append(textarea);
td.append(button);
button.onclick = () => updateReply(replyNo, textarea);
}
=> 자바스크립트 객체를 JSON 형식으로 보내야한다!!!
$.ajax({ url : '${contextPath}/reply/update/'+replyNo, data : JSON.stringify(reply), // JSON 문자열 형태로 변환시켜서 전달 type : 'PUT', contentType : 'application/json;charset=UTF-8', success : function(result){ if(result > 0){ alert("수정성공") selectReplyList(); }else{ alert("수정실패") } } }) |
// 자바스크립트 객체를 JSON 형식으로 보내야함
function updateReply(replyNo, textarea){
let reply = {
replyNo,
replyContent : textarea.value
};
$.ajax({
url : '${contextPath}/reply/update/'+replyNo,
data : JSON.stringify(reply), // JSON 문자열 형태로 변환시켜서 전달
type : 'PUT',
contentType : 'application/json;charset=UTF-8',
success : function(result){
if(result > 0){
alert("수정성공")
selectReplyList();
}else{
alert("수정실패")
}
}
})
}
▶ ReplyController.java
=> 댓글 내용이 보이게 하려면 RequestBody를 추가하여야함
=> 댓글 등록 및 수정에서도 XSS핸들링, 개행처리 해줘야한다!! XSS 공격을 막기위해서 현재는 그냥 진행
@PutMapping("/update/{replyNo}") // url로 전달받은 자원을 PathVariable 이용해서 뽑아옴
public int updateReply(@PathVariable("replyNo") int replyNo,
@RequestBody Reply r) {
log.info("reply ? {}", r);
return service.updateReply(r);
}
▶ ReplyService.java
int updateReply(Reply r);
▶ ReplyServiceImpl.java
@Override
public int updateReply(Reply r) {
return replyDao.updateReply(r);
}
▶ ReplyDao.java
int updateReply(Reply r);
▶ ReplyDaoImpl.java
@Override
public int updateReply(Reply r) {
return sqlSession.update("replyMapper.updateReply", r);
}
▶ reply-mapper.xml
<!-- 댓글 수정 -->
<update id="updateReply" parameterType="reply" >
UPDATE REPLY
SET REPLY_CONTENT = #{replyContent}
WHERE REPLY_NO = #{replyNo}
</update>
4. 댓글 삭제
▶ boardDetailVeiw.jsp
function deleteReply(replyNo){
if(confirm('정말로 댓글을 삭제하겠습니까?')) {
$.ajax({
url : '${contextPath}/reply/delete/'+replyNo,
data : {replyNo},
type : 'delete',
success : function(result){
if(result > 0){
alert("삭제성공")
selectReplyList();
}else{
alert("삭제실패")
}
}
})
}
}
▶ ReplyController.java
// @PostMapping("/delete")
@DeleteMapping("/delete/{replyNo}")
public int deleteReply(@PathVariable("replyNo") int replyNo) {
return service.deleteReply(replyNo);
}
▶ ReplyService.java
int deleteReply(int replyNo);
▶ ReplyServiceImpl.java
@Override
public int deleteReply(int replyNo) {
return replyDao.deleteReply(replyNo);
}
▶ ReplyDao.java
int deleteReply(int replyNo);
▶ ReplyDaoImpl.java
@Override
public int deleteReply(int replyNo) {
return sqlSession.delete("replyMapper.deleteReply", replyNo);
}
▶ reply-mapper.xml
<delete id="deleteReply" parameterType='int'>
DELETE FROM REPLY
WHERE REPLY_NO = #{replyNo}
</delete>
▶ 결과
'Server > Spring' 카테고리의 다른 글
[Spring] 10-2. 채팅방 참여, 인원수 증가, 메세지 조회 (0) | 2024.01.29 |
---|---|
[Spring] 10-1. 채팅방 목록, 채팅방 생성 (0) | 2024.01.29 |
[Spring] 8-5. 게시판 수정하기(+ 사진삭제, 사진수정, 사진추가) (0) | 2024.01.26 |
[Spring] 8-4. 첨부파일 사진 다운로드 (0) | 2024.01.25 |
[Spring] 8-3. 일반 게시판 상세보기, 조회수 증가 (0) | 2024.01.25 |