본문 바로가기
멀티캠퍼스 풀스택 과정/백엔드

Spring:14 글 내용에서 댓글 등록,수정,삭제 구현(DB설계와연동)-1

by 이쟝 2022. 3. 21.

 

1. DB설계 

외래키 설정

1:n -> reviewboard noINT와 board no INT 연결
     -> reviewboard userid VARCHAR(45)와 member userid VARCHAR(45)와 연결


2. 댓글을 ajax로 구현할 것이어서 Ajax 환경설정

pom.xml


<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
		<dependency>
		    <groupId>com.google.code.gson</groupId>
		    <artifactId>gson</artifactId>
		    <version>2.9.0</version>
		</dependency>

3. 댓글 등록 폼 세팅하기(DB와 연동하기)

1. 글 내용 폼 + script로 댓글 등록 폼을 만든다. 

bullentinBrdView.jsp

<script>
$(function(){
	// 댓글 등록
	("#reviewFrm").on('submit', function(){
		event.preventDefault(); // form 기본이벤트 제거
});

<!-- 댓글 쓰기 -->
	<!-- desc reviewboard의 컬럼명과 맞게한다. -->
    <c:if test="${logInStatus=='Y'}"> <!-- 로그인했을때만 보이기 -->
        <form method="post" id="reviewFrm"> <!-- 화면전환 x action x -->
            <input type="hidden" name="no"><!-- 원글 글번호(board 테이블의 no -->
            <textarea name="content" id="content" style="width:500px; height:80px;"></textarea>
            <input type="submit" value="등록"/>
        </form>
    </c:if>

2. VO 클래스를 생성한다.(DB 컬럼명과 동일하게)

package com.mycampus.myappy.vo;

public class ReviewVO {
	
	private int reviewno;
	private int no;
	private String userid;
	private String content;
	private String createdate;
	
	public int getReviewno() {
		return reviewno;
	}
	public void setReviewno(int reviewno) {
		this.reviewno = reviewno;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getCreatedate() {
		return createdate;
	}
	public void setCreatedate(String createdate) {
		this.createdate = createdate;
	}
}

3. DAO에 미리 댓글 등록, 목록, 수정, 삭제 메서드를 정의한다.

package com.mycampus.myappy.dao;

import java.util.List;

import com.mycampus.myappy.vo.ReviewVO;

public interface ReviewDAO {
	// 댓글 등록
	public int reviewWrite(ReviewVO vo);

	// 댓글 목록
	// 원글 글 번호(no)를 매개변수로 받아서 리스트로 폼을 가져온다.
	public List<ReviewVO> reviewList(int no);
	
	// 댓글 수정
	// 댓글 번호(reviewno), 로그인 아이디(userid), 수정할 내용(content)
	public int reviewEdit(ReviewVO vo);
	
	// 댓글 삭제 
	// ReviewVO vo로 매개변수를 받아도 된다. 
	public int reviewDelete(int reviewno, String userid);
}

4. Service, ServiceImpl, Mapper.xml, Controller를 구현한다.

package com.mycampus.myappy.service;

import java.util.List;

import com.mycampus.myappy.vo.ReviewVO;

public interface ReviewService {
	// 댓글 등록
	public int reviewWrite(ReviewVO vo);

	// 댓글 목록
	public List<ReviewVO> reviewList(int no);
	
	// 댓글 수정
	public int reviewEdit(ReviewVO vo);
	
	// 댓글 삭제 
	public int reviewDelete(int reviewno, String userid);
}
package com.mycampus.myappy.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mycampus.myappy.dao.ReviewDAO;
import com.mycampus.myappy.vo.ReviewVO;

@Service
public class ReviewServiceImpl implements ReviewService {
	@Autowired
	ReviewDAO dao;
	
	@Override
	public int reviewWrite(ReviewVO vo) {
		return dao.reviewWrite(vo);
	}

	@Override
	public List<ReviewVO> reviewList(int no) {
		return dao.reviewList(no);
	}

	@Override
	public int reviewEdit(ReviewVO vo) {
		return dao.reviewEdit(vo);
	}

	@Override
	public int reviewDelete(int reviewno, String userid) {
		return dao.reviewDelete(reviewno, userid);
	}
}
<?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="com.mycampus.myappy.dao.ReviewDAO">
	<insert id="reviewWrite">
	</insert>
	<select id="reviewList">
	</select>
	<update id="reviewEdit">
	</update>
	<delete id="reviewDelete">
	</delete>
</mapper>
package com.mycampus.myappy.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import com.mycampus.myappy.service.ReviewService;

@RestController  // responseBody를 하지 않기 위해서
public class ReviewController {
	
	@Autowired
	ReviewService service;
}

5-1. 글 내용 폼으로 돌아와서 유효성 검사를 한다.(데이터가 있으면 작업)

bulletinBrdView.jsp

데이터가 넘어오는 지 콘솔 작업을 먼저 한다. 

serialize( ): jquery가 가지고 있는 기본 기능 중에 하나로 form을 대상으로 serialize( )를 사용하면 폼의 객체들을 한 번에 반들 수 있다.
ajax에 data 값을 세팅할 때 사용하면 해당 form의 모든 값을 쉽게 받을 수 있다. (name1=value&name2=value2..)
// 댓글 구현
$(function(){
	// 댓글 등록
	("#reviewFrm").on('submit', function(){
		event.preventDefault(); // form 기본이벤트 제거
		
		if($("#content").val()==''){ // 댓글을 입력하지 않은 경우
			alert("댓글을 입력 후 등록하세요");
			return;   // 함수 실행 중단
		}else{  // 댓글 입력한 경우
			let params = $("#reviewFrm").serialize();
		
			//Ajax호출
			$.ajax({
				url : '/myappy/review/reviewWriteOk', // 맵핑 주소 임의 생성, 비동기 식으로 접속
				data : params,
				type : 'POST',
				success : function(result){ // 서버에서 받은 데이터는 result로
					console.log("result : ", result);
				}, error : function(e){
					console.log(e.reponseText); // 에러가나면 에러메시지 콘솔에
				}
			})
		}
	});
});

 

5-2. Controller로 돌아가서 reviewWriteOk(댓글 등록할) 맵핑 주소를 연결한다. 

package com.mycampus.myappy.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.mycampus.myappy.service.ReviewService;
import com.mycampus.myappy.vo.ReviewVO;

@RestController  // responseBody를 하지 않기 위해서
public class ReviewController {
	
	@Autowired
	ReviewService service;
	
	// 댓글 등록 맵핑 주소
	@RequestMapping(value="/review/reviewWriteOk", method=RequestMethod.POST)
	public int writeOk(ReviewVO vo, HttpSession session) {
		// 세션에 있는 아이디 구하기
		vo.setUserid((String)session.getAttribute("logId"));
		return service.reviewWrite(vo);
	}
}

5-3. Mapper.xml에 쿼리문 작성하기

reviewno은 autoincrease로 자동 생성되고, createdate도 자동 생성되기 때문에 no, userid, content만 등록하면 된다.

?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="com.mycampus.myappy.dao.ReviewDAO">
	<insert id="reviewWrite">
		insert into reviewboard(no, userid, content)
		values(#{no}, #{userid}, #{content})
	</insert>
</mapper>

등록버튼을 누르면 console에 1이 찍힌다.&nbsp;


4. 댓글 쓰기 폼 리스트로 보여주기

1. 글 내용 폼(뷰페이지) 에서 댓글 목록을 보여주는 함수를 구현한다.(js로)

1) 로그인을 해야 댓글이 보인다.
2) 댓글을 쓴 아이디와 접속한 아이디가 같아야 수정과 삭제 버튼이 보인다. 댓글 폼 중간에 if문으로 구현
// 댓글 목록(reviewList)을 가져오는 함수
function reviewAllList(){  // 현재 보고있는 글의 모든 댓글목록 가져오기
    let url = "/myappy/review/list";
    let params = "no=${vo.no}";     // 원글
    $.ajax({
        url:url,
        data:params,
        success:function(r){
            //list안에 들어와있는것은 선택해서 반복문 처리
            let result = $(r);  // vo, vo, vo, ... controller의 return값

            let tag = "<ul>";
            result.each(function(idx, vo){ // 첫번째 매개변수 index, 두번째 매개변수 vo(데이터)
                tag += "<li><div>" + vo.userid + " (" + vo.createdate + ") ";

                // 왼쪽은 문자로 인식 오른쪽은 변수로 인식 ''가 쳐지게 만들어야 함 
                if(vo.userid == '${logId}'){ 
                    tag += "<input type='button' value='Edit'/>";
                    tag += " <input type='button' value='Delete' title='"+vo.reviewno+"'/>";
                }
                tag += "<br/>" + vo.content + "</div><hr/></li>";
            });
            tag += "</ul>";
            $("#reviewList").html(tag);
        }
    });
}
// 댓글 등록
$("#reviewFrm").on('submit',function(){
    event.preventDefault(); // form 기본이벤트 제거
    if($("#content").val()==''){ // 댓글을 입력하지 않은 경우
        alert("댓글을 입력 후 등록하세요");
        return;   // 함수 실행 중단
    }else{  // 댓글 입력한 경우
        let params = $("#reviewFrm").serialize();
        //Ajax호출
        $.ajax({
            url : '/myappy/review/writeOk', // 맵핑 주소 임의 생성, 비동기 식으로 접속
            data : params,
            type : 'POST',
            success: function(result){ // 서버에서 받은 데이터는 result로
                // 댓글 폼을 초기화
                $("#content").val("");
                // 댓글 목록 보이기
                reviewAllList();
            },error : function(e){
                console.log(e.responseText); // 에러가나면 에러메시지 콘솔에
            }
        });
    }
});
reviewAllList(); // 댓글 목록 항상 보이기(글내용을볼때)
});

2. Mapper.xml에서 리스트를 보여주는 쿼리문을 작성한다.

매개변수로 현재 보고있는 글(no)을 받고 그 글에 맞는 댓글 번호(reviewno), 아이디(userid), 내용(content), 날짜(createdate)를 가져온다. 
원글 글 번호(no)를 매개변수로 받아서 리스트로 폼을 가져온다. public List<ReviewVO> reviewList(int no);
<?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="com.mycampus.myappy.dao.ReviewDAO">
	<select id="reviewList" resultType="com.mycampus.myappy.vo.ReviewVO">
		select reviewno, userid, content, createdate 
		from reviewboard where no=${param1} order by reviewno desc
	</select>
</mapper>

3. Controller를 구현한다. 

package com.mycampus.myappy.controller;

@RestController  // responseBody를 하지 않기 위해서
public class ReviewController {
	
	@Autowired
	ReviewService service;

	// 댓글 목록 맵핑 주소
	@GetMapping("/review/list")
	public List<ReviewVO> reviewList(int no){ // 원글(no)
		return service.reviewList(no);
        // List를 return (변수에 담아서 보내줄 필요 xx)
	}
}

5. 댓글 폼 수정버튼 누르면 수정 폼을 보게 하기

앞에서 본인 댓글일때만 수정과 삭제 버튼을 보게 했다. 수정 버튼을 누르면 display:none이 되었던 게 display:block이 되면서 수정 폼을 보게 해줘야 한다. 

$.ajax({
    url:url,
    data:params,
    success:function(r){
        //list안에 들어와있는것은 선택해서 반복문 처리
        let result = $(r);  // vo, vo, vo, ... controller의 return값

        let tag = "<ul>";
        result.each(function(idx, vo){ // 첫번째 매개변수 index, 두번째 매개변수 vo(데이터)
            tag += "<li><div>" + vo.userid + " (" + vo.createdate + ") ";

            // 왼쪽은 문자로 인식 오른쪽은 변수로 인식 ''가 쳐지게 만들어야 함 
            if(vo.userid == '${logId}'){ 
                tag += "<input type='button' value='Edit'/>";
                tag += " <input type='button' value='Delete' title='"+vo.reviewno+"'/>";
            }
            tag += "<br/>" + vo.content + "</div>";

            // 본인글일 때 수정폼이 보이기 
            if(vo.userid=='${logId}'){
            	tag += "<div style='display:none'><form method='post'>";
            	tag += "<input type='hidden' name='reviewno' value='"+vo.reviewno+"'/>";
            	tag += "<textarea name='content' style='width:400px; height:50px;'>"+vo.content+"</textarea>";
            	tag += " <input type='submit' value='수정'/></form></div>";
            }	
            tag += "<hr/></li>"; 
        });
        tag += "</ul>";
        $("#reviewList").html(tag);
    	}
	});
}
// 댓글 수정버튼 선택시 수정 폼 보여주기(document로 이벤트를 해서 처리)
// reviewList에서 input이 value가 수정인 것을 선택
$(document).on('click', '#reviewList input[value=Edit]', function(){
    // this의 부모 숨기기<div> -> this는 input[value=Edit]
    $(this).parent().css("display","none"); // 댓글폼을 안보이게 한다.
    // 수정폼을 보여주기 
    $(this).parent().next().css("display","blocK"); // 수정폼을 보이게 한다.
})
reviewAllList();


5. 댓글 폼 수정 작업을 DB와 연동하기

1. 먼저 view페이지에서 댓글 수정폼을 db와 연동하는 것을 js로 구현한다.

// 댓글 수정폼 (DB)
$(document).on('submit', '#reviewList form', function(){
    event.preventDefault(); // post방식 action xx
    $.ajax({
        url : '/myappy/review/editOk', 
        data : $(this).serialize(),
        type : 'POST',
        success : function(result){
            reviewAllList();
        }, error : function(e){
            console.log("수정에러");
        }
    });
});

2. Mapper.xml에서 수정하는 쿼리문을 작성한다.

내용(content)을 바꾸기 위해서 댓글 번호(reviewno)와 아이디(userid)가 같아야 한다.(vo객체로 받았다.) 반환형은 int! public int reviewEdit(ReviewVO vo);

<?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="com.mycampus.myappy.dao.ReviewDAO">
	<update id="reviewEdit">
		update reviewboard set content=#{content} 
		where reviewno=${reviewno} and userid=#{userid}
	</update>
</mapper>

3. Controller를 구현한다. 

package com.mycampus.myappy.controller;

@RestController  // responseBody를 하지 않기 위해서
public class ReviewController {
	
	@Autowired
	ReviewService service;
	
	// 댓글 수정 폼 DB 연동
	@PostMapping(value="/review/editOk")
	public int editOk(ReviewVO vo, HttpSession session) {
		vo.setUserid((String)session.getAttribute("logId"));
		return service.reviewEdit(vo);
	}
}

6. 댓글 폼 삭제 작업을 DB와 연동하기

1. 먼저 view페이지에서 댓글 수정폼을 db와 연동하는 것을 js로 구현한다.

	// 댓글 삭제
	$(document).on('click', '#reviewList input[value=Delete]', function(){
		if(confirm("댓글을 삭제하시겠습니까?")){ //확인:true, 취소:false
			let params = "reviewno="+$(this).attr("title");
			$.ajax({
				url: '/myappy/review/delete',
				data : params,
				success : function(result){
					reviewAllList();
				},error : function(){
					console.log("댓글삭제에러!")
				}
			});
		}	
	});
	reviewAllList();

2. Mapper.xml에서 삭제하는 쿼리문을 작성한다.

삭제하기 위해서 댓글 번호(reviewno)와 아이디(userid)를 매개변수로 받는다. 반환형은 int!

public int reviewDelete(int reviewno, String userid); (insert update delete의 반환형은 int)

<?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="com.campus.myapp.dao.ReplyDAO">
	<delete id="replyDel">
		delete from replyboard where replyno=#{param1} and userid=#{param2}
	</delete>
</mapper>

 

3. Controller를 구현한다. 

package com.mycampus.myappy.controller;

@RestController  // responseBody를 하지 않기 위해서
public class ReviewController {
	
	@Autowired
	ReviewService service;
	
	// 댓글 삭제 
	@GetMapping("/review/delete")
	public int deleteOk(int reviewno, HttpSession session) {
		return service.reviewDelete(reviewno, (String)session.getAttribute("logId"));
	}
}