[싱글이의 영수증] 댓글 등록,신고

업데이트:

싱글이의 영수증 댓글 등록

  • 출력화면

image



CSS

<style>

/* 댓글 */
.card {
	position: relative;
	display: flex;
	flex-direction: column;
	min-width: 0;
	word-wrap: break-word;
	background-color: #fff;
	background-clip: border-box;
	border: 1px solid #d2d2dc;
}

.media img {
	width: 30px;
	height: 30px;
}

.reReply {
	clear: both;
}

/*  댓글 작성 */
.createReply {
	height: 150px;
	background-color: honeydew;
}

.textArea {
	width: 100%;
	height: 110px;
	resize: none;
	padding: 10px;
}

/* 답글 */
.childReply{
	padding-left: 50px;  
}

.childReplyArea{
	padding-top : 30px;
	width : 100%;
  text-align: right;
}

.childReplyContent{
	resize: none;  
	width : 100%; 
}

.replyUpdateContent {
	resize: none;
	width: 100%;
}


/* 댓글 등록/취소 버튼  */

.maincolor1{
    color: #ffffff !important; 
    background-color:#4ab34a !important;
    border: 1px solid #4ab34a !important;
}
.maincolor1:hover{
    color: #ffffff !important; 
    background-color:#4ca975 !important;
    border: 1px solid #4ca975 !important;
}

/* 버튼 반대로 : 흰 바탕, 주황 테두리 */
.maincolor-re1{
        color: #4ab34a !important;
        background-color: #ffffff !important;
        border: 1px solid #4ab34a !important;
}
.maincolor-re1:hover{
    color: #ffffff !important; 
    background-color:#4ca975 !important;
    border: 1px solid #4ca975 !important;
}


/* 댓글 수정 삭제 버튼  */
.maincolor2{
    color: #228b22 !important; 
    background-color: !important;
    border: none !important;
}
.maincolor2:hover{
    color: #4ca975 !important; 
    border: none !important;
    cursor : pointer;
}

/* 버튼 반대로 : 흰 바탕, 주황 테두리 */
.maincolor-re2{
        color: #228b22 !important;
        background-color: none !important;
        border: none !important;
}
.maincolor-re2:hover{
    color: #4ca975 !important; 
    border: none !important;
    cursor : pointer;
}
</style>



JSP

댓글은 댓글 출력 부분 영역 지정, 댓글 작성창 제외 다른 부분은 전부 AJAX를 이용해서 비동기로 처리함.

<div class="row bg-light" style="margin-top: 15px;">
    <div class="col-md-12">
        <div class="row">
            <div class="col-md-12">
            
                <!-- 댓글 출력 부분 -->
                <div class="replyListArea">
                </div>
            
                <!-- 댓글 작성창 -->
                /* 등급 아이콘 출력 */
                <div class="p-2">
                    <div class="d-flex flex-row align-items-start">
                        <c:if test="${loginMember.memberGrade=='F' }">
                            <img class="image" src="${contextPath}/resources/images/grade1.png" width="40" />
                        </c:if>
                        <c:if test="${loginMember.memberGrade=='S' }">
                            <img class="image" src="${contextPath}/resources/images/grade2.png" width="40" />
                        </c:if>
                        <c:if test="${loginMember.memberGrade=='T' }">
                            <img class="image" src="${contextPath}/resources/images/grade3.png" width="40" />
                        </c:if>
                        <c:if test="${loginMember.memberGrade=='G' }">
                            <img class="image" src="${contextPath}/resources/images/gradeG.png" width="40" />
                        </c:if>

                        <textarea class="form-control ml-1 shadow-none textarea" id="replyContent" style="resize: none"> </textarea>
                    </div>
                    <div class="mt-2 text-right">
                        <button class="btn btn-primary btn-sm shadow-none  maincolor1"  id="addReply">등록</button>
                        <button class="btn btn-outline-primary btn-sm ml-1 shadow-none maincolor-re1" id="resetReply" type="button">취소</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>



script

  • 데이터 얻어오기

댓글을 등록한 회원 번호와, 댓글이 등록될 게시글 번호, 출력될 유저의 닉네임을 받아온다

var memberNo = "${loginMember.memberNo}";
var parentBoardNo = "${review.boardNo}";

var nickName = "${loginMember.memberNickname}"



  • 페이지 로딩 완료 시 댓글 목록 호출

레디 함수로 댓글 목록 불러오는 함수를 호출 해 페이지 로딩 완료 시 댓글 목록이 호출되도록 한다.

$(function(){
    selectReplyList();
});



  • 댓글 목록 불러오기

댓글 목록 불러오기 함수는 해당 게시글 번호를 매개변수로 게시글 번호가 일치하는 댓글의 목록을 조회한다.

댓글 목록 조회를 성공하게되면 댓글을 담아둔 list를 반복 접근해서 댓글이 나올 수 있는 html코드를 append해준다
댓글의 깊이가 1인 요소는 답글로 처리가 되어야하기 때문에 별도의 클래스를 추가하고,
댓글의 깊이가 0인 요소는 댓글로 답글 버튼이 추가한다.
자기의 댓글이 아닌 경우 신고 버튼을 추가, 자신의 댓글인 경우에는 수정,삭제 버튼을 추가한다

function selectReplyList(){
    $.ajax({
        url : "${contextPath}/reviewReply/selectReplyList/" + parentBoardNo,
        type : "post",
        dataType : "json",
        success : function(rList){
            var replyListArea = $(".replyListArea");

            // 기존 정보 초기화
            replyListArea.html("");
            // 댓글 List 반복 접근
            $.each(rList, function(index, item){
                
                var media = $("<div>").addClass("media mt-2").css({"border-bottom-color": "lightgray", "border-bottom-style":"solid", "border-bottom-width":"thin"});
                
                // 이미지
                var memberGrade = item.memberGrade;
                var img = null;
                    if(memberGrade == 'F'){
                        img = $("<img>").addClass("mr-3 rounded-circle").attr("src", "${contextPath}/resources/images/grade1.png").css({"width": "30px;","height": "30px;"});
                    }else if(memberGrade=='S'){
                        img = $("<img>").addClass("mr-3 rounded-circle").attr("src", "${contextPath}/resources/images/grade2.png").css({"width": "30px;","height": "30px;"});						 
                    }else if(memberGrade=="T"){
                        img = $("<img>").addClass("mr-3 rounded-circle").attr("src", "${contextPath}/resources/images/grade3.png").css({"width": "30px;","height": "30px;"});						 
                    }else{
                        img = $("<img>").addClass("mr-3 rounded-circle").attr("src", "${contextPath}/resources/images/gradeG.png").css({"width": "30px;","height": "30px;"});							 
                    }
                // 작성자, 작성일 영역
                var mediaBody = $("<div>").addClass("media-body");
                var row = $("<div>").addClass("row");
                var col8 = $("<div>").addClass("col-8 d-flex");
                var nickname = $("<h6>").css({"margin-right":"5px", "font-weight":"5px"}).html(item.nickName);
                var createDt = $("<span>").css({"color":"gray", "font-size": "12px"}).html(item.replyCreateDt);
                
                // 답글, 신고 버튼 영역
                var col4 = $("<div>").addClass("col-4");
                var floatRight = $("<div>").addClass("reply float-right");
                var reply2 = $("<a>").addClass("childReply maincolor2").css({"margin-right":"5px"}).attr("onclick", "addChildReplyArea(this, "+ item.parentReplyNo + ")").text("답글");
                var report = $("<a class='replyReport maincolor2'>").attr("href", "javascript:void(0)").attr("onclick", "openReport("+item.replyNo+")").text("신고");
                
                // 내용 영역
                var replyText = $("<div>").addClass("replyText").css({"margin-bottom":"5px"}).html(item.replyContent);
                
                var floatRight2 = $("<div>").addClass("float-right").attr("style", "font-size: 13px;");
                var replyUpdate = $("<a>").addClass("replyUpdate maincolor2").css({"margin-right":"5px"}).attr("onclick", "showUpdateReply(" + item.replyNo + ", this)").text("수정");
                var replyDelete = $("<a>").addClass("replyDelete maincolor-re2").attr("onclick", "deleteReply(" + item.replyNo + ")").text("삭제");
                
                // 댓글의 깊이가 1인 요소는 별도의 스타일을 지정할 수 있도록 클래스 추가
                if(item.replyDepth == 1){
                    media.addClass("childReply");
                }
                
                // 댓글의 깊이가 0인 요소 답글 버튼 추가
                if(item.replyDepth == 0){
                    floatRight.append(reply2);
                }
                
                // 로그인이 되어 있고, 자신의 글이 아닐 경우에 신고 버튼 추가
                if(memberNo != "" && item.memberNo != memberNo){
                    col8.append(nickname).append(createDt);
                    floatRight.append(report);
                    col4.append(floatRight);
                    row.append(col8).append(col4);
                    mediaBody.append(row);
                    mediaBody.append(replyText);
                    media.append(img).append(mediaBody);
                    replyListArea.append(media);
            
                // 현재 댓글의 작성자와 로그인한 멤버의 아이디가 같을 때 수정/삭제 버튼 추가
                }else if(item.memberNo == memberNo){
                    col8.append(nickname).append(createDt);
                    row.append(col8);
                    mediaBody.append(row);
                    mediaBody.append(replyText);
                    floatRight2.append(replyUpdate).append(replyDelete);
                    mediaBody.append(floatRight2);
                    media.append(img).append(mediaBody);
                    replyListArea.append(media);
                }
            });
        }, error : function(){
                console.log("댓글 목록 조회 실패")
            }
    });
}


Controller

package com.gaji.SingleBungle.review.controller;

@Controller
@SessionAttributes({"loginMember"})
@RequestMapping("/reviewReply/*")
public class ReviewReplyController {
	
	@Autowired
	private ReviewReplyService service;

	
	private String swalIcon = null;
	private String swalTitle = null;
	private String swalText = null;
	
	// 댓글 목록 조회
	@ResponseBody
	@RequestMapping("selectReplyList/{parentBoardNo}")
	public String selectReplyList(@PathVariable("parentBoardNo") int parentBoardNo) {
		
		List<ReviewReply> rList = service.selectReplyList(parentBoardNo);
		
		Gson gson = new GsonBuilder().setDateFormat("yyyy년 MM월 dd일 HH:mm:ss").create();
		
		return gson.toJson(rList);
	}

Service

List<ReviewReply> selectReplyList(int parentBoardNo);

ServiceImpl

@Override
public List<ReviewReply> selectReplyList(int parentBoardNo) {
    return dao.selectReplyList(parentBoardNo);
}

DAO

public List<ReviewReply> selectReplyList(int parentBoardNo) {
    return sqlSession.selectList("reviewReplyMapper.selectReplyList", parentBoardNo);
}

Mapper


댓글을 조회해 올 때 부모 게시글 번호와 일치하는 댓글을 가져오고, 부모 댓글 번호와 일치하는 답글을 가져온다.
최신 댓글이 가장 상단에 보일 수 있게 부모 댓글 번호 순으로 내림차순 정렬한다
만약 부모 댓글 번호와 댓글 번호가 같다면 999999999라는 큰 숫자를 지정해주고 아니라면 그냥 일반 댓글 번호로 남겨 둔 후 오름차순 한다
(부모댓글번호 = 일반 댓글이 가장 상단에 위치하게 됨).

<select id="selectReplyList" parameterType="_int" resultMap="reply_rm">
    SELECT * FROM V_BOARD_REPLY
    WHERE REPLY_STATUS = 'N'
    AND PARENT_BOARD_NO = #{parentBoardNo}
    AND PARENT_REPLY_NO IN ( SELECT REPLY_NO FROM	V_BOARD_REPLY
                            WHERE REPLY_STATUS = 'N'
                            AND REPLY_DEPTH = 0
                            AND PARENT_BOARD_NO = #{parentBoardNo})
    ORDER BY PARENT_REPLY_NO DESC,
            CASE WHEN PARENT_REPLY_NO = REPLY_NO THEN 99999999
            ELSE REPLY_NO END DESC
</select>



  • 댓글 등록

로그인이 되어있지 않다면, 로그인을 해주세요 라는 alert창이 뜬다.

$("#addReply").on("click",function(){
    
    if(memberNo == 0){
        swal({icon : "info", title : "로그인 후 이용해 주세요."});
    }else{
        var replyContent = $("#replyContent").val();
        
        if(replyContent.trim().length == 0){
            swal({icon:"info", title:"댓글을 작성해 주세요."});
        }else{
            $.ajax({
                url : "${contextPath}/reviewReply/insertReplyList/" + parentBoardNo,
                type : "post",
                data : {"memberNo":memberNo, "replyContent":replyContent},
                success : function(result){
                    if(result>0){
                        $("#replyContent").val("");
                        swal({icon:"success", title:"댓글이 작성되었습니다."});
                        selectReplyList();
                    }
                }, error : function(){
                    console.log("댓글 작성 실패");
                }
            });
        }
    }
});


Controller


댓글 작성 창은 textarea이기 때문에 크로스 사이트 스크립팅을 방지하기 위해서 개행문자와 꺽쇠등을 변경해준 후 insert를 진행한다

@ResponseBody
@RequestMapping("insertReplyList/{parentBoardNo}")
public int insertReply(@PathVariable("parentBoardNo") int parentBoardNo, @ModelAttribute("reply") ReviewReply reply) {
    
    reply.setParentBoardNo(parentBoardNo);
    
    return service.insertReply(reply);
}

Service

int insertReply(ReviewReply reply);

ServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int insertReply(ReviewReply reply) {
    reply.setReplyContent(replaceParameter (reply.getReplyContent()));
    reply.setReplyContent(reply.getReplyContent().replaceAll("\n", "<br>"));
    
    return dao.insertReply(reply);
}

DAO

public int insertReply(ReviewReply reply) {
    return sqlSession.insert("reviewReplyMapper.insertReply", reply);
}

Mapper

<insert id="insertReply" parameterType="ReviewReply">
    INSERT INTO BOARD_REPLY(REPLY_NO, REPLY_CONTENT, MEM_NO, PARENT_BOARD_NO, PARENT_REPLY_NO)
    VALUES(SEQ_BRNO.NEXTVAL, #{replyContent}, #{memberNo}, #{parentBoardNo} , SEQ_BRNO.CURRVAL)
</insert>
  • 크로스 사이트 스크립트 방지 메소드
// 크로스 사이트 스크립트 방지 메소드
private String replaceParameter(String param) {
    
    String result = param;
    
    if(param !=null) {
        result = result.replaceAll("&", "&amp;");
        result = result.replaceAll("<", "&lt;");
        result = result.replaceAll(">", "&gt;");
        result = result.replaceAll("\"", "&quot;"); 
    }
    
    return result;
    
}



  • 댓글 등록 취소
$("#resetReply").on("click",function(){
    $("#replyContent").val("");
});



  • 댓글 수정 화면

댓글 수정창을 열었는데 이미 댓글 수정 폼이 열려있다면 하나의 수정 폼만 열리도록 이미 열려있는 댓글 수정 창을 닫는다.

수정창에 기존에 작성한 내용을 불러온다.
수정 창에 작성되는 내용을 다시 코로스사이트 스크립트 처리를 해제시킨다.

var beforeReplyRow;

function showUpdateReply(replyNo,el){
    
    
    // 이미 열려있는 댓글 수정 창이 있을 경우 닫아주기
    if($(".replyUpdateContent").length > 0){
        $(".replyUpdateContent").eq(0).parent().html(beforeReplyRow);
    }		

    
    // 댓글 수정화면 출력 전 요소 저장
    beforeReplyRow = $(el).parent().parent().html();
    
    // 작성되어있던 내용
    var beforeContent = $(el).parent().prev().html();

    // 이전 댓글 내용의 크로스사이트 스크립트 처리 해제, 개행문자 변경
    // -> 자바스크립트에는 replaceAll() 메소드가 없으므로 정규 표현식을 이용하여 변경
    beforeContent = beforeContent.replace(/&amp;/g, "&");   
    beforeContent = beforeContent.replace(/&lt;/g, "<");   
    beforeContent = beforeContent.replace(/&gt;/g, ">");   
    beforeContent = beforeContent.replace(/&quot;/g, "\"");   
    
    beforeContent = beforeContent.replace(/<br>/g, "\n");   		

    
    // 기존 댓글 영역을 삭제하고 textarea를 추가
    $(el).parent().prev().remove();
    var textarea = $("<textarea>").addClass("replyUpdateContent").attr("rows", "3").val(beforeContent);
    $(el).parent().before(textarea);
    
    // 수정 버튼
    var updateReply = $("<button>").addClass("btn btn-sm ml-1 mb-4 maincolor1").text("댓글 수정").attr("onclick", "updateReply(" + replyNo + ", this)");
    
    // 취소 버튼
    var cancelBtn = $("<button>").addClass("btn btn-sm ml-1 mb-4 maincolor-re1").text("취소").attr("onclick", "updateCancel(this)");
    
    var replyBtnArea = $(el).parent();
    
    $(replyBtnArea).empty(); 
    $(replyBtnArea).append(updateReply); 
    $(replyBtnArea).append(cancelBtn); 	  
    
}



  • 댓글 수정
// 댓글 수정
function updateReply(replyNo, el){
    var replyContent = $(el).parent().prev().val();
    if(replyContent.trim().length == 0){
        swal({icon : "info", title : "댓글을 입력해주세요."});
    }else{
        $.ajax({
            url : "${contextPath}/reviewReply/updateReply/" + replyNo,
            type : "post",
            data : {"replyContent" : replyContent},
            success : function(result){
                if(result > 0){
                    swal({icon : "success", title : "댓글 수정 성공"});
                    selectReplyList();
                }
            }, error : function(){
                console.log("댓글 수정 실패");
            }
        });
    }
}


Controller


수정된 댓글을 등록할 때 역시 크로스 사이트 스크립팅 방지처리를 한 후 insert를 진행해야 한다.

@ResponseBody
@RequestMapping("updateReply/{replyNo}")
public int updateReply(@PathVariable("replyNo") int replyNo, 
                        @ModelAttribute("reply") ReviewReply reply) {
    
    reply.setReplyNo(replyNo);
    
    return service.updateReply(reply);
}

Service

int updateReply(ReviewReply reply);

ServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int updateReply(ReviewReply reply) {
    reply.setReplyContent( replaceParameter( reply.getReplyContent() ) );
    reply.setReplyContent( reply.getReplyContent().replaceAll("\n", "<br>"));		
    
    return dao.updateReply(reply);
}

DAO

public int updateReply(ReviewReply reply) {
    return sqlSession.update("reviewReplyMapper.updateReply", reply);
}

Mapper

<update id="updateReply" parameterType="ReviewReply">
UPDATE BOARD_REPLY SET
REPLY_CONTENT = #{replyContent}
WHERE REPLY_NO = #{replyNo}
</update>



  • 댓글 수정 취소 시 원래대로 돌아가기
function updateCancel(el){
    $(el).parent().parent().html(beforeReplyRow);
}	



  • 댓글 삭제
	function deleteReply(replyNo){
	if(confirm("정말로 삭제하시겠습니까?")){
		$.ajax({
			url : "${contextPath}/reviewReply/deleteReply/" + replyNo,
			success : function(result){
				
				if(result>0){
					swal({icon : "success", title:"댓글 삭제 성공"});
					selectReplyList();
				}
			}, error : function(){
				console.log("댓글 삭제 실패");
			}
		});
	}
}

Controller

@ResponseBody
@RequestMapping("deleteReply/{replyNo}")
public int deleteReply(@PathVariable("replyNo") int replyNo) {
    return service.deleteReply(replyNo);
}

Service

int deleteReply(int replyNo);

ServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int deleteReply(int replyNo) {
    return dao.deleteReply(replyNo);
}

DAO

public int deleteReply(int replyNo) {
    return sqlSession.update("reviewReplyMapper.deleteReply", replyNo);
}

Mapper

<update id="deleteReply" parameterType="_int">
    UPDATE BOARD_REPLY SET
    REPLY_STATUS = 'Y'
    WHERE REPLY_NO = #{replyNo}
</update>



  • 답글 버튼
// 답글 버튼 동작(대댓글 작성 영역 생성)
function addChildReplyArea(el, parentReplyNo){
    
    // 생성되어 있는 모든 답글 작성 영역을 화면에서 제거
    var check = cancelChildReply();
    
    // 이전에 생성된 대댓글 영역이 모두 삭제된 경우에만 새로운 대댓글 영역 생성
    if(check){
        
        // 댓글 작성자 닉네임 얻어오기
        var writer = $(el).parent().parent().prev().children("h6").text();
        
        
        // 답글 작성 영역에 필요한 요소(textarea, button 2개) 생성
        
        var div = $("<div>").addClass("childReplyArea"); // 대댓글 작성 영역 전체를 감쌀 div
        var textarea = $("<textarea rows='3'>").
                    addClass("childReplyContent").attr("placeholder", writer + "님께 답글 작성하기");
        
        var btnArea = $("<div>").addClass("btnArea");
        var insertBtn = $("<button>").addClass("btn btn-sm  ml-1 maincolor1").text("등록")
        .attr("onclick", "addChildReply(this, " + parentReplyNo + ")");
        
        var cancelBtn = $("<button>").addClass("btn btn-sm  ml-1 reply-cancel maincolor-re1").text("취소")
        .attr("onclick", "cancelChildReply()");
        
        btnArea.append(insertBtn).append(cancelBtn); // 버튼 영역에 등록, 취소 버튼 추가
        div.append(textarea).append(btnArea); // 대댓글 영역에 textarea, 버튼 영역 추가
        
        $(el).parent().parent().parent().parent().parent().after().after(div); // 답글 버튼 부모 요소 다음(이후)에 대댓글 영역 추가
        
        // 추가된 대댓글 영역으로 포커스 이동
        $(".childReplyContent").focus();
    }
}



  • 답글 작성 취소


답글 취소 버튼을 눌렀을 경우, 생성된 답글 창이 닫히고, 글자가 쓰여져있을경우 confirm창이 뜬다.

function cancelChildReply(){
    
    // 대댓글 영역에 작성된 내용 얻어오기
    var tmp = $(".childReplyContent").val();
    
    // 대댓글 textarea에 아무것도 작성되지 않았거나, 대댓글 textarea가 없을 경우
    // == 아무것도 작성되지 않으면 confirm창으로 확인하는 과정 없이 바로 닫히게 만듦.
    if(tmp == "" || tmp == undefined){
        // 대댓글 작성 영역 childReplyArea을 모두 제거
        $(".childReplyArea").remove();
    return true;
    }
    else{ // 답글 textarea에 무언가 작성되어 있을 경우
        var cancelConfirm = confirm("작성된 댓글 내용이 사라집니다. 작성 취소 하시겠습니까?");
        if(cancelConfirm){
            $(".childReplyArea").remove();
        }
        return cancelConfirm;
    }
}



  • 답글 작성
function addChildReply(el, parentReplyNo){
    var replyContent =	$(el).parent().prev().val();
    if(replyContent.trim().length == 0){ // 대댓글 미작성 시
        swal({icon : "info", title : "댓글 작성 후 클릭해주세요"});
    }
    else{
        $.ajax({
            url : "${contextPath}/reviewReply/insertChildReply/" + parentBoardNo,
            data : {"parentReplyNo" : parentReplyNo,
                            "replyContent" : replyContent,
                            "memberNo" : memberNo},
                            type : "post",
            success : function(result){
                
                if(result > 0){
                    swal({icon : "success", title : "답글 등록 성공"});
                    selectReplyList();
                }
            }, error : function(){
                console.log("답글 등록 실패");
            }
        });		
    }
}	

Controller

@ResponseBody
@RequestMapping("insertChildReply/{parentBoardNo}")
public int insertChildReply(@PathVariable("parentBoardNo") int parentBoardNo, @ModelAttribute("reply") ReviewReply reply) {
    reply.setParentBoardNo(parentBoardNo);
    return service.insertChildReply(reply);
}

Service

int insertChildReply(ReviewReply reply);

ServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int insertChildReply(ReviewReply reply) {
    return dao.insertChildReply(reply);
}

DAO

public int insertChildReply(ReviewReply reply) {
    
    return sqlSession.update("reviewReplyMapper.insertChildReply", reply);
}

Mapper

<insert id="insertChildReply" parameterType="ReviewReply">
    INSERT INTO BOARD_REPLY(REPLY_NO, REPLY_CONTENT, REPLY_DEPTH, MEM_NO, PARENT_BOARD_NO, PARENT_REPLY_NO)
    VALUES(SEQ_BRNO.NEXTVAL, #{replyContent}, 1,  #{memberNo}, #{parentBoardNo} , #{parentReplyNo} )
</insert>



싱글이의 영수증 댓글 신고

댓글 신고 페이지 연결

Controller

@RequestMapping("reviewReplyReport/{replyNo}")
public String replyReport(@PathVariable int replyNo, Model model) {
    model.addAttribute("replyNo", replyNo);
    
    return "review/reviewReplyReport";
}

jsp

<style>
	    .maincolor{
        color: #ffffff !important; 
        background-color:#ffaf18 !important;
        border: 1px solid #ffaf18 !important;
    }
    .maincolor:hover{
        color: #ffffff !important; 
        background-color:#ff8500 !important;
        border: 1px solid #ffc823 !important;
    }

    /* 버튼 반대로 : 흰 바탕, 주황 테두리 */
    .maincolor-re{
            color: #ff8500 !important;
            background-color: #ffffff !important;
            border: 1px solid #ffaf18 !important;
    }
    .maincolor-re:hover{
        color: #ffffff !important; 
        background-color:#ff8500 !important;
        border: 1px solid #ffc823 !important;
    }
</style>
</head>
<body>
<c:if test="${swalIcon == 'success' }">
	<script>
		swal({icon : "${swalIcon}",
		 title : "${swalTitle}",
		 text : "${swalText}"}).then(function(){close()});
	</script>
</c:if>
<c:if test="${swalIcon == 'error' }">
	<script>
		swal({icon : "${swalIcon}",
		 title : "${swalTitle}",
		 text : "${swalText}"});
	</script>
</c:if>
   <div class="container my-5" style="padding-left: 40px; padding-right: 40px;">
     <form method="POST" action="../reviewReplyReportAction" class="needs-validation" name="report">
     <input type="hidden" name="replyNo" value="${replyNo }">
     <input type="hidden" name="boardNo" value="${param.boardNo }">
     <div class="form-group row">
      <label for="recipient-name" class="col-sm-3 col-form-label">신고 제목</label>
       <div class="col-sm-9">
             <input type="text" class="form-control" id="recipient-name" name="reportTitle" placeholder="신고 제목을 입력해 주세요." autocomplete="off" required>
          </div>
     </div>

         <div class="form-group row">
             <label class="input-group-addon col-sm-3 insert-label">신고 사유</label>
             <div class="col-sm-9">
             <select class="form-control div small" id="category" name="categoryCode" required>
                 <option value="1">욕설, 비방, 차별, 혐오</option>
                 <option value="2">홍보, 영리목적</option>
                 <option value="3">불법 정보</option>
                 <option value="4">음란, 청소년 유해</option>
                 <option value="5">개인 정보 노출, 유포, 거래</option>
                 <option value="6">도배, 스팸</option>
                 <option value="7">기타</option>
             </select>
             </div>
         </div>


         <div class="form-group row">
             <label for="content" class="col-sm-3 col-form-label">신고 내용</label>
             <div class="col-sm-9">
             <textarea class="form-control" id="summernote" name="reportContent" rows="10" style="resize: none;" required></textarea>
             </div>
         </div>
         <div class="form-group row">
               <div class="col-sm-12" style="text-align:center; margin-top:30px;">
                <button type="submit" class="btn maincolor">신고</button>
                <button class="btn maincolor-re" onclick="self.close();">취소</button>
             </div>
         </div>
     </form>
    </div>
</body>



댓글 신고 등록

Controller

@RequestMapping("reviewReplyReportAction")
public String insertReplyReport(@ModelAttribute ReviewReplyReport report, @RequestParam("replyNo") int replyNo,
            @RequestParam("boardNo") int boardNo, @ModelAttribute(name="loginMember", binding=false) Member loginMember,
            HttpServletRequest request, RedirectAttributes ra) {
    
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("memberNo", loginMember.getMemberNo());
    map.put("boardNo", boardNo);
    map.put("replyNo", replyNo);
    
    map.put("reportTitle", report.getReportTitle());
    map.put("reportContent", report.getReportContent());
    map.put("categoryCode", report.getCategoryCode());
    
    int result = service.insertReviewReplyReport(map);
    
    String url = "redirect:" + request.getHeader("referer");
    
    if(result>0) {
        swalIcon = "success";
        swalTitle = "신고가 접수되었습니다.";
    }else {
        swalIcon = "error";
        swalTitle="신고 접수 실패";
    }
    ra.addFlashAttribute("swalIcon",swalIcon);
    ra.addFlashAttribute("swalTitle", swalTitle);
    return url;
}

Service

int insertReviewReplyReport(Map<String, Object> map);

ServiceImpl

@Transactional(rollbackFor = Exception.class)
@Override
public int insertReviewReplyReport(Map<String, Object> map) {
    
    int result =0;
    
    int reportNo = dao.selectReportNo();
    
    if (reportNo>0) {
        map.put("reportNo",reportNo);
        
        String reportTitle = (String)map.get("reportTitle");
        String reportContent = (String)map.get("reportContent");
        
        reportTitle = replaceParameter(reportTitle);
        reportContent = replaceParameter(reportContent);
        
        map.put("reportTitle", reportTitle);
        map.put("reportContent", reportContent);
    }
    
    result = dao.insertReviewReplyReport(map);
    
    if(result>0) {
        result = reportNo;
    }
    
    return result;
}
  • 신고 번호 얻어오기

DAO

public int selectReportNo() {
    return sqlSession.selectOne("reviewReplyMapper.selectReportNo");
}

Mapper

<select id="selectReportNo" resultType="_int">
    SELECT SEQ_RNO.NEXTVAL FROM DUAL
</select>
  • 신고하기

DAO

public int insertReviewReplyReport(Map<String, Object> map) {
    return sqlSession.insert("reviewReplyMapper.insertReviewReplyReport", map);
}

Mapper

<insert id="insertReviewReplyReport" parameterType="map">
    INSERT INTO REPORT_REPLY 
    VALUES(#{reportNo}, #{reportTitle}, #{reportContent}, 
    #{memberNo}, #{categoryCode}, #{replyNo}, #{boardNo})
</insert>



댓글남기기