댓글 작성 Mapper
<!-- 댓글 작성 -->
<insert id="reply_Insert" parameterType="replyVO">
INSERT INTO replytable(
reply_idx
,reply_content
,id
,reply_wdate
,reply_ip
,bidx
,uidx
,board_type
,rparent
)VALUES(
reply_idx_seq.nextval
,#{reply_Content}
,#{id}
,SYSDATE
,#{reply_Ip}
,#{bidx}
,#{uidx}
,#{board_type}
,reply_idx_seq.nextval
)
</insert>
댓글 목록 Mapper
<!-- 커뮤니티 댓글 목록 -->
<select id="reply_list" resultType="replyVO" parameterType="int">
SELECT reply_idx
,reply_content
,id
,reply_wdate
,bidx
,uidx
,rdepth
,rparent
FROM replytable
WHERE bidx = #{bidx}
AND board_type = 0
ORDER BY rparent asc, reply_wdate asc
</select>
대댓글을 달은 댓글 밑에 대댓글 리스트를 작성 순서대로 출력하려면 부모댓글과 작성날짜를 정렬했어야했다.
댓글 삭제 Mapper
<!-- 댓글 삭제 -->
<delete id="deleteByReply" parameterType="replyVO">
DELETE replytable
WHERE reply_idx = #{reply_Idx}
</delete>
댓글 수정 Mapper
<!-- 댓글 수정 -->
<update id="updateByReply" parameterType="replyVO">
UPDATE replytable
SET reply_content = #{reply_Content}
WHERE reply_idx = #{reply_Idx}
</update>
대댓글 작성 Mapper
<!-- 대댓글 작성 -->
<insert id="re_replyInsert" parameterType="replyVO">
INSERT into replytable (
reply_idx
,reply_content
,id
,reply_wdate
,reply_ip
,bidx
,uidx
,board_type
,rdepth
,rparent
)
VALUES (
reply_idx_seq.nextval
,#{reply_Content}
,#{id}
,SYSDATE
,#{reply_Ip}
,#{bidx}
,#{uidx}
,0
,1
,#{rparent}
)
</insert>
대댓글과 댓글의 구분을 위해 대댓글 입력시 rdepth를 1로 입력했다.
DAO
@Repository
public class ReplyDAO {
@Autowired
private SqlSession sqlSession;
//댓글작성
public int reply_Insert(ReplyVO replyVO) {
return sqlSession.insert("project.healingcamp.mapper.replyMapper.reply_Insert", replyVO);
}
//커뮤니티 댓글 목록
public List<ReplyVO> reply_list(int bidx){
return sqlSession.selectList("project.healingcamp.mapper.replyMapper.reply_list",bidx);
}
//상담사 게시판 댓글 목록
public List<ReplyVO> counseller_reply_list(int bidx){
return sqlSession.selectList("project.healingcamp.mapper.replyMapper.counseller_reply_list",bidx);
}
//댓글 삭제
public int deleteByReply(ReplyVO replyVO) {
return sqlSession.delete("project.healingcamp.mapper.replyMapper.deleteByReply", replyVO);
}
//댓글 수정
public int updateByReply(ReplyVO replyVO) {
return sqlSession.update("project.healingcamp.mapper.replyMapper.updateByReply", replyVO);
}
//대댓글 작성
public int re_replyInsert(ReplyVO replyVO) {
return sqlSession.insert("project.healingcamp.mapper.replyMapper.re_replyInsert",replyVO);
}
}
Service(interface)
public interface ReplyService {
//댓글 작성
int reply_Insert(ReplyVO replyVO);
//댓글리스트
List<ReplyVO> reply_list(int bidx);
//댓글 삭제
int deleteByReply(ReplyVO replyVO);
//댓글 수정
int updateByReply(ReplyVO replyVO);
//대댓글 작성
int re_replyInsert(ReplyVO replyVO);
}
Service
@Service
public class ReplyServiceImpl implements ReplyService {
@Autowired
private ReplyDAO replyDAO;
@Autowired
private Community_BoardDAO cboardDAO;
//댓글 작성
//Community_BoardDAO 사용을 위한 트랜잭션
@Transactional
@Override
public int reply_Insert(ReplyVO replyVO) {
cboardDAO.addReplyCnt(replyVO.getBidx()); // 댓글 작성시 댓글 카운트 +1
return replyDAO.reply_Insert(replyVO);
}
//댓글 리스트
@Override
public List<ReplyVO> reply_list(int bidx) {
List<ReplyVO> reply_list = replyDAO.reply_list(bidx);
return reply_list;
}
//댓글 삭제
@Transactional
@Override
public int deleteByReply(ReplyVO replyVO) {
cboardDAO.removeReplyCnt(replyVO.getBidx()); //댓글 삭제 댓글카운트 -1
return replyDAO.deleteByReply(replyVO);
}
//댓글 수정
@Override
public int updateByReply(ReplyVO replyVO) {
return replyDAO.updateByReply(replyVO);
}
//대댓글 작성
@Transactional
@Override
public int re_replyInsert(ReplyVO replyVO) {
cboardDAO.addReplyCnt(replyVO.getBidx()); // 대댓글 작성시 카운트+1
return replyDAO.re_replyInsert(replyVO);
}
VO
public class ReplyVO {
private int reply_Idx; //댓글 번호
private String reply_Content; //댓글 내용
private String id; //댓글 작성한 아이디
private String reply_Wdate; //댓글 작성 날짜
private String reply_Ip; //댓글 작성 ip
private int bidx; //댓글 작성한 게시글 번호
private int uidx; //댓글 작성한 회원의 uidx
private int board_type; //게시판 유형
private int rdepth; //댓글 - rdepth:0 , 대댓글 - rdepth:1
private int rparent; //부모 댓글
getter / setter 생성
Controller
//댓글 작성
@RequestMapping(value="/community_write.do",method=RequestMethod.POST)
public String community_write(Community_BoardVO cboardVO,HttpSession session,HttpServletRequest request) {
UserVo login = (UserVo)session.getAttribute("login");
cboardVO.setId(login.getId());
cboardVO.setUidx(login.getUidx());
cboardVO.setIp(request.getRemoteAddr());
//게시글 작성
cboardService.insert(cboardVO);
//최근작성한 게시글의 bidx
int bidx = cboardService.maxBidx();
return "redirect:community_view.do?bidx="+bidx;
}
//댓글 리스트
@RequestMapping(value="/community_replyList.do",method=RequestMethod.GET)
@ResponseBody
public List<ReplyVO> community_view(int bidx) {
//댓글 리스트
List<ReplyVO> reply_list = replyService.reply_list(bidx);
return reply_list;
}
//댓글 삭제
@RequestMapping(value="/community_reply_delete.do",method=RequestMethod.POST)
@ResponseBody
public String community_reply_delete(ReplyVO replyVO) {
replyService.deleteByReply(replyVO);
return "1";
}
//댓글 수정
@RequestMapping(value="/community_reply_update.do",method=RequestMethod.POST)
@ResponseBody
public String community_reply_update(@RequestBody ReplyVO replyVO) {
replyService.updateByReply(replyVO);
return "1";
}
//댓글 신고 팝업창
@RequestMapping(value="/reply_popup.do",method=RequestMethod.GET)
public String reply_popup() {
return "community/reply_popup";
}
//대댓글 작성
@RequestMapping(value="community_re_reply.do",method=RequestMethod.POST)
@ResponseBody
public String re_replyInsert(@RequestBody ReplyVO replyVO, HttpSession session, HttpServletRequest request,Community_BoardVO cboardVO) {
//로그인 정보
UserVo login = (UserVo)session.getAttribute("login");
replyVO.setId(login.getId()); //대댓글 작성자 아이디
replyVO.setUidx(login.getUidx()); //대댓글 작성자 uidx
replyVO.setReply_Ip(request.getRemoteAddr()); //ip
replyService.re_replyInsert(replyVO);
return "1";
}
JavaScript
댓글 작성
//로그인 정보
var login = "${login}";
//현재 로그인한아이디
var id = '<%=session.getAttribute("id")%>';
// 댓글 작성 버튼 클릭
$(document).on("click","#reply_btn",function(){
//댓글 입력값
var reply = $("textarea[name=reply_Content]").val();
//로그인 여부
if(login == ""){
alert("로그인 후 이용해주세요");
return false;
}
//댓글 작성여부
else if(reply == ""){
alert("댓글을 입력해주세요.");
return false;
}
//댓글작성
$.ajax({
type:"post",
url:"community_reply_insert.do",
data:$("#commentForm").serialize(),
dataType:"text",
success:function(data){
if(data == "success"){
$("#reply").val("");
getCommentList(); //댓글 작성 완료시 댓글 목록함수 호출
}
},error:function(){
alert("error");
}
});
});
//초기페이지 로딩시 댓글 불러오기
$(function(){
getCommentList();
});
댓글 목록
//댓글목록
function getCommentList(){
//작성하려는 댓글의 게시물 번호
var bidx = $("input[name=bidx]").val();
$.ajax({
type:"get",
url:"community_replyList.do",
data:"bidx="+bidx,
success : function(result){
var html="";
if(result.length > 0){
for(i = 0; i < result.length; i++){
var reply_Idx = result[i].reply_Idx; //댓글번호
var bidx = result[i].bidx; // 댓글이 달린 게시글 번호
var reply_Content = result[i].reply_Content; //댓글 내용
var writer = result[i].id //댓글 작성자
var rdepth = result[i].rdepth //댓글깊이
var rparent = result[i].rparent;
console.log(rparent);
html += "<div class='reply_area"+rparent+"'>";
if(reply_Content == ""){ //삭제된 댓글일때
html += "<dlv>";
html += "<div>삭제된 댓글입니다.</div>"
html += "</dlv>";
}else{
if(rdepth == 0){//댓글일때
html += "<div class='reply_box'>";
html += "<div class='reply_box_wrapper"+reply_Idx+"'>"; //댓글 수정 버튼 클릭시 수정 창으로 바뀌는 부분(수정하려는 댓글의 idx)
html += "<div class='reply_info_wrapper'>";
html += "<ul class='reply_info'>";
html += "<li class='id'>"+result[i].id+"</li>";
html += "<li class='wdate'>"+result[i].reply_Wdate+"</li>";
if(id == result[i].id){ //현재 로그인된 아이디일시 댓글수정가능
html += "<li class='commentModify' onclick='commentModify("+reply_Idx+",\""+reply_Content+"\",\""+writer+"\");'>댓글수정</li>";
}else{
html += "<li class='re_reply' onclick='re_reply("+reply_Idx+","+bidx+")'>답글쓰기</li>";
}
if(id == result[i].id){//현재 로그인된 아이디일시 댓글삭제가능
html += "<li class='delete' onclick='deleteReply("+reply_Idx+","+bidx+");'>삭제</li>";
}else{
html += "<li class='report' onclick='reportReply()'>신고</li>";
}
html += "</ul>"; //.reply_info
html += "</div>"; //.reply_info_wrapper
html += "<div class='reply_view_wrapper'>";
html += "<div class='reply_view'>"+result[i].reply_Content+"</div>";
html += "</div>"; //.reply_view_wrapper
html += "</div>"; //.reply_box_wrapper
html += "</div>"; //.reply_box
html += "<div class='re_reply_area"+reply_Idx+"'></div>"; //답글작성이 들어갈 칸
}else{//대댓글일때
html += "<div class='re_reply_box'>";
html += "<div class='reply_box_wrapper"+reply_Idx+"'>"; //답글 수정 버튼 클릭시 수정 창으로 바뀌는 부분(수정하려는 답글의 idx)
html += "<span class='reply_ico'>└</span>";
html += "<div class='reply_info_wrapper' >";
html += "<ul class='reply_info'>";
html += "<li class='id'>"+result[i].id+"</li>";
html += "<li class='wdate'>"+result[i].reply_Wdate+"</li>";
if(id == result[i].id){
html += "<li class='commentModify' onclick='commentModify("+reply_Idx+",\""+reply_Content+"\",\""+writer+"\");'>댓글수정</li>";
}else{
html += "<li class='re_reply' onclick='re_reply("+reply_Idx+","+bidx+")'>답글쓰기</li>";
}
if(id == result[i].id){
html += "<li class='delete' onclick='deleteReply("+reply_Idx+","+bidx+");'>삭제</li>";
}else{
html += "<li class='report' onclick='reportReply()'>신고</li>";
}
html += "</ul>"; //.reply_info
html += "</div>"; //.reply_info_wrapper
html += "<div class='reply_view_wrapper'>";
html += "<div class='reply_view'>"+result[i].reply_Content+"</div>";
html += "</div>"; //.reply_view_wrapper
html += "</div>"; //.reply_box_wrapper
html += "</div>"; //.re_reply_box
}
}
html += "</div>"; //.reply_area
}
}else{
html += "<div>등록된 댓글이 없습니다.</div>";
}
$("#reply_wrapper").html(html);
},error:function(){
alert("error");
}
});
}
댓글 삭제
//댓글 삭제
function deleteReply(reply_Idx,bidx){
var ans = confirm("선택하신 댓글을 삭제하시겠습니까?");
if(!ans){return false;}
$.ajax({
type:"post",
url:"community_reply_delete.do",
data:{"reply_Idx":reply_Idx,"bidx":bidx},
success:function(data){
if(data == 1){
alert("삭제가 완료되었습니다.");
location.reload();
}
},error:function(){
alert("댓글 삭제 실패");
}
});
}
댓글 수정
//댓글 수정창띄우기
function commentModify(reply_Idx,reply_Content,writer){
var comment = ""
comment +="<div class='reply_info_wrapper' >";
comment += "<ul class='reply_info'>";
comment += "<li class='id'>"+writer+"</li>";
comment += "<li class='commentModify' onclick='updateBtn("+reply_Idx+",\""+reply_Content+"\");'>댓글수정</li>";
comment += "<li class='cancel' onclick='getCommentList();'>취소</li>";
comment += "</ul>";
comment +="</div>"; //취소버튼 클릭시 댓글 목록리스트 함수 실행
comment +="<div class='reply_view_wrapper'>";
comment += "<textarea id='reply_Edit_Content' name='reply_Content' style='width:100%;'>"+reply_Content+"</textarea>";
comment +="</div>";
$(".reply_box_wrapper"+reply_Idx).replaceWith(comment);
}
//댓글 수정
function updateBtn(reply_Idx,reply_Content){
var reply_Content = $("textarea[name='reply_Content']").val(); //수정된 댓글 내용
if(reply_Content == ""){
alert("내용을 입력해주세요.");
}else{
$.ajax({
url:"community_reply_update.do",
type:"post",
data:JSON.stringify({ "reply_Idx":reply_Idx ,"reply_Content":reply_Content}),
dataType:"json",
contentType : "application/json;charset=UTF-8",
success:function(result){
if(result == 1){
alert("댓글 수정이 완료되었습니다.");
getCommentList();//댓글 수정완료시 댓글 목록리스트 함수 실행
}
},error:function(){
alert("error");
}
});
}
}
대댓글
//대댓글창 띄우기
function re_reply(reply_Idx,bidx){
if(login == ""){
alert("로그인 후 이용해주세요.");
}else{
var reply = "";
reply += "<div class='re_reply_box'>";
reply += "<span class='reply_ico'>└</span>";
reply += "<div class='reply_info_wrapper' >";
reply += "<ul class='reply_info'>";
reply += "<li class='id'>"+id+"</li>";
reply += "<li class='re_reply_btn' onclick='re_reply_btn("+reply_Idx+","+bidx+");'>댓글등록</li>";
reply += "<li class='cancel' onclick='getCommentList();'>취소</li>";//취소버튼 클릭시 댓글 목록리스트 함수 실행
reply += "</ul>";
reply += "</div>";
reply += "<div class='reply_view_wrapper'>";
reply += "<textarea id='reply_Edit_Content' name='reply_Content' style='width:100%;'></textarea>";
reply += "<input type='hidden' name='rparent' value="+reply_Idx+">";
reply += "</div>";
reply += "</div>";
$(".re_reply_area"+reply_Idx).html(reply);
}
//display 여부에 따라 show,hide
if($(".re_reply_area"+reply_Idx).css("display") == "none"){
$(".re_reply_area"+reply_Idx).show();
}else{
$(".re_reply_area"+reply_Idx).hide();
}
}
대댓글 등록
//대댓글 등록
function re_reply_btn(reply_Idx,bidx){
var reply_Content = $("textarea[name='reply_Content']").val();
var rparent = $("input[name=rparent]").val();
if(reply_Content == ""){
alert("내용을 입력해주세요.");
}else{
$.ajax({
url:"community_re_reply.do",
type:"post",
data:JSON.stringify({"reply_Content":reply_Content, "bidx":bidx,"rparent":rparent}), //rparent:대댓글 다는 댓글의 idx
dataType:"json",
contentType:"application/json; charset=UTF-8",
success:function(result){
getCommentList(); //대댓글 입력시 댓글목록함수 호출
},error:function(){
alert("error");
}
});
}
}
로그인을 하지 않고 답글쓰기 클릭시 로그인 후 이용하라는 경고창이 뜬다.
답글쓰기 클릭시 답글 밑에 답글 입력창이 나타남
답글등록 완료 후 답글을 등록한 댓글 밑에 작성한 순서대로 답글이 출력된다.
드디어 완성 해서 넘뿌듯뿌듯~~!
이번에 댓글 기능을 만들면서 느낀것은
ajax로 html을 뿌려줄때 태그의 열림닫힘 표시를 잘 해두자...............헷갈려죽는 줄
https://gimmesome.tistory.com/176
Spring MVC 로 댓글(답글) 구현하기
사진자랑 게시판(게시판명: picture)의 '댓글' 기능을 예로 들었다. picture 게시판에선 카드리스트에서 카드를 클릭하면 나오는 모달창에서 댓글 아이콘을 클릭해야 댓글들을 볼 수 있고, 댓글과 대
gimmesome.tistory.com
댓글 기능 구현시 참고했던 포스팅!!
'Board > 개인프로젝트' 카테고리의 다른 글
[JAVA]개행 문자 처리하기 (2) | 2023.02.14 |
---|---|
팝업창 띄우기 (0) | 2023.02.08 |
[spring] ajax 게시판 댓글 기능 구현 (3) | 2023.02.06 |
jquery onclick,hover 같이 사용하기 (0) | 2023.02.02 |
개인프로젝트 회원가입페이지 가상경로 띄우고 데이터 전송까지 (0) | 2022.11.30 |