[Spring]오늘의 직방 - 리뷰, 평점 작성

dh·2022년 11월 9일
0
post-thumbnail

리뷰 작성

지도에서 아파트 마커를 클릭시 매물에 대한 정보와 리뷰를 작성하고 볼수 있도록 했습니다.
로그인시 session에 회원의 정보를 넣어 놓고, 리뷰작성 버튼 클릭시 session을 확인하여 로그인한 사용자만 리뷰를 작성하도록 했습니다.
리뷰작성은 모달창을 띄어 작성하도록 하고 모달창 안의 내용은 공백으로 초기화해 비워둡니다.
내용을 입력 후 ajax로 전송해 DB에 저장을 했습니다.
그리고 작성한 리뷰가 맨 위에 보이도록 원래 화면에 있던 리뷰들을 지웠다가 page를 1로 다시 설정하고 리뷰리스트를 다시 호출하였습니다.

코드

리뷰리스트에서 리뷰작성하기 버튼 클릭

writeReview.addEventListener("click",function(){
    
    console.log(writeReview.value)
    if(writeReview.value==""){
        
        //alert("로그인이 필요합니다.")
        Swal.fire({
            title: "로그인이 필요합니다.",  // title, text , html  로 글 작성
            icon: "error",    //상황에 맞는 아이콘
            showCancelButton: true,
            showConfirmButton: false,
            cancelButtonText: '확인'
        }).then(result => {
            // 만약 Promise리턴을 받으면,
               window.location.href='/member/login'
         });
         return false
        
    }else{
        $('#exampleModal').modal('show')
    }
// 모달창안의 내용 초기화
    addReview.style.display="block"
    updateReview.style.display="none"
    grade_text.value=""
    trf_text.value=""
    env_text.value=""
    res_text.value=""
    reviewNum.value=""
    $("input:radio[name='recommend']").prop('checked',false);
    $("input:radio[name='trf']").prop('checked',false);
    $("input:radio[name='env']").prop('checked',false);
    $("input:radio[name='res']").prop('checked',false);
})

모달창안에서 리뷰작성 버튼

// 리뷰 작성
addReview.addEventListener("click",function(){
    let gv
    let tgv
    let egv
    let rgv
    let recommend = document.getElementsByName("recommend")
    for(let i=0; i<recommend.length;i++){
        if(recommend[i].checked){
            gv=recommend[i].value
        }
    }
    let trf = document.getElementsByName("trf")
    for(let i=0; i<trf.length;i++){
        if(trf[i].checked){
            tgv=trf[i].value
        }
    }
    let env = document.getElementsByName("env")
    for(let i=0; i<env.length;i++){
        if(env[i].checked){
            egv=env[i].value
        }
    }
    let res = document.getElementsByName("res")
    for(let i=0; i<res.length;i++){
        if(res[i].checked){
            rgv=res[i].value
        }
    }

    let num = maemulNum.value
    let id = userId.value
    let gtv = grade_text.value
    let ttv = trf_text.value
    let etv = env_text.value
    let rtv = res_text.value
    let road = roadname.value

    let xhttp= new XMLHttpRequest();
    xhttp.open("POST","./addReview");
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send("num="+num+"&userId="+id+"&grade="+gv+"&contents="+gtv+"&trfGrade="+tgv+"&trfContents="+ttv+"&envGrade="+egv+"&envContents="+etv+"&resGrade="+rgv+"&resContents="+rtv);
    xhttp.addEventListener("readystatechange",function(){
        if(xhttp.status==200 && xhttp.readyState==4){
            let result = xhttp.responseText;
            if(result==1){
                for(let i=0; i<houseReviewList.children.length;){
                    houseReviewList.children[0].remove();
                }
                reviewPage=1;					// 첫번째 페이지로 설정 
                getReviewList(road,reviewPage)	// 리뷰리스트 호출

            }
        }
    });

});

결과


리뷰 목록

ajax로 도로명주소와 페이지번호를 보내 해당 아파트의 리뷰를 받아와 javascript로 element를 생성합니다.

코드

//리뷰리스트
function getReviewList(roadName,p){
    let xhttp = new XMLHttpRequest();
    xhttp.open("GET","./getHouseReview?roadName="+roadName+"&page="+p);
    xhttp.send();
    xhttp.addEventListener("readystatechange",function(){
        if(xhttp.status==200 && xhttp.readyState==4){
            var result = JSON.parse(xhttp.responseText.trim());
  
            let list= result.list
            let pager=result.maemulPager

            if(list.length==0){
                let revDiv = document.createElement("div")
                revDiv.className="revDiv"
                let div = document.createElement("div")
                div.className="userDiv"
                div.innerText="아직 리뷰가 없습니다."
                revDiv.appendChild(div)
                houseReviewList.appendChild(revDiv)
            }

            for(let i=0; i<list.length; i++){
                
                //리뷰 element 생성 코드 생략 .......

                revDiv.appendChild(updel)

                houseReviewList.appendChild(revDiv)

                //페이지 없으면 버튼 비활성화
                if(reviewPage >= pager.totalPage){
                    reviewMore.disabled= true;
                    reviewMore.className='disabled'
                }else{
                    reviewMore.disabled= false;
                    reviewMore.className='more'
                }
                reviewMore.setAttribute("data-name",roadName)
            
            }
        }
    });
}

//리뷰 더보기
reviewMore.addEventListener("click", function(){
    reviewPage++
    let roadName = reviewMore.getAttribute("data-name");
    getReviewList(roadName,reviewPage)
});

리뷰 수정,삭제

리뷰 작성시 수정과 삭제 element를 만들 때 update.setAttribute("value",list[i].userId) del.setAttribute("value",list[i].userId)와 같이 userId의 값을 속성으로 부여했습니다.

그래서 수정이나 삭제를 클릭할 시 writerCheck 인터셉터를 실행하여 작성자를 확인하도록 했습니다.
writerCheck() 함수는 세션의 값을 확인해 로그인하지 않은 상태면 로그인 페이지로 이동하고 로그인한 상태면 ajax로 userId를 보내 작성자를 확인하도록 합니다.

//작성자확인 인터셉터
function writerCheck(userId){
    let result
    if(writeReview.value==""){
        //alert("로그인이 필요합니다.")
        Swal.fire({
            title: "로그인이 필요합니다.",  // title, text , html  로 글 작성
            icon: "error",    //상황에 맞는 아이콘
            showCancelButton: true,
            showConfirmButton: false,
            cancelButtonText: '확인'
        }).then(result => {
            // 만약 Promise리턴을 받으면,
               window.location.href='/member/login'    
         });
    }

    $.ajax({
        type: "post",
        url: "./writerCheck",
        async: false,     //값을 리턴시 해당코드를 추가하여 동기로 변경
        data: { userId: userId },
        success: function (data) {
            result = data;
        }
    });
    return result
}

servlet-context에 wrtierCheckInterceptor와 인터셉터가 발생할 url을 등록합니다.
/apt/writerCheck라는 url요청이 오면 요청을 가로채서 writerCheckInterceptor객체가 실행됩니다.

servlet-context.xml

	<beans:bean class="com.goodee.home.interceptor.WriterCheckInterceptor" id="writerCheckInterceptor"></beans:bean>
    <interceptors>
		<interceptor>
			<mapping path="/apt/writerCheck"/>
			<beans:ref bean="writerCheckInterceptor"/>
		</interceptor>	
	</interceptors>

AptController

	@PostMapping("writerCheck")
	@ResponseBody
	public ModelAndView writerCheck(HouseReviewDTO houseReviewDTO)throws Exception{
		System.out.println("컨트롤러"+houseReviewDTO.getUserId());
		ModelAndView mv = new ModelAndView();
		mv.addObject("houseReviewDTO",houseReviewDTO);
		return mv;
	}

writerCheckInterceptor

public class WriterCheckInterceptor extends HandlerInterceptorAdapter {

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		boolean check = true;
		
		HttpSession session = request.getSession();
		
		MemberDTO memberDTO = (MemberDTO)session.getAttribute("member");
		
		Map<String, Object> map = modelAndView.getModel();

		HouseReviewDTO houseReviewDTO =(HouseReviewDTO)map.get("houseReviewDTO");
		System.out.println("포스트인터셉터 로그인"+memberDTO.getUserId());
		System.out.println("포스트인터셉터 작성자"+houseReviewDTO.getUserId());
		
		if(!memberDTO.getUserId().equals(houseReviewDTO.getUserId())) {
			System.out.println("일치하지 않음");
			modelAndView.setViewName("common/ajaxResult");
			modelAndView.addObject("result",0);
		}else {
			modelAndView.setViewName("common/ajaxResult");
			modelAndView.addObject("result",1);
		}	
	}
}

postHandle()을 사용해 컨트롤러 실행후 DispatcherServlet으로 가기 전에 WriterCheckInterceptor를 실행합니다. session에서 회원의 userId를 받아오고 컨트롤러에서 추가한 houseReviewDTO에서 userId를 받아서 둘을 비교합니다. 그 결과로 일치하면 1, 일치하지 않으면 0을 리턴합니다.
작성자가 아닐시 alert 창 표시.

수정을 눌러 리뷰작성하기작성자가 일치하면 리뷰를 작성할때와 같은 모달창이 뜨는데 이때는 작성했던 리뷰의 내용이 들어가 있습니다.

houseReviewList.addEventListener("click",function(event){   
    if(event.target.className=="update"){
     	// WrtierCheck 실행
        let result = writerCheck(event.target.getAttribute("value"));
        console.log(result)
        if(result==null){
            return false
        }
        if(result==0){
            Swal.fire({
                title: "작성자만 수정이 가능합니다.",  // title, text , html로 글 작성
                icon: "warning",    //상황에 맞는 아이콘
                showCancelButton: true,
                showConfirmButton: false,
                cancelButtonText: '확인'
            })
            return false
        }
        
        grade_text.value=event.target.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.lastChild.innerHTML
        trf_text.value=event.target.parentNode.previousSibling.previousSibling.previousSibling.lastChild.innerHTML
        env_text.value=event.target.parentNode.previousSibling.previousSibling.lastChild.innerHTML
        res_text.value=event.target.parentNode.previousSibling.lastChild.innerHTML
        reviewNum.value=event.target.parentNode.parentNode.getAttribute("data-rvnum")
        let grade=event.target.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.firstChild.firstChild.nextSibling.innerHTML
        let tg = event.target.parentNode.previousSibling.previousSibling.previousSibling.firstChild.firstChild.nextSibling.innerHTML
        let eg = event.target.parentNode.previousSibling.previousSibling.firstChild.firstChild.nextSibling.innerHTML
        let rg = event.target.parentNode.previousSibling.firstChild.firstChild.nextSibling.innerHTML
        
        document.getElementsByName("recommend")[Math.abs(grade-5)].checked=true
        document.getElementsByName("trf")[Math.abs(tg-5)].checked=true
        document.getElementsByName("env")[Math.abs(eg-5)].checked=true
        document.getElementsByName("res")[Math.abs(rg-5)].checked=true
        upReview.click()
    }
})

그리고 모달창에 리뷰작성 버튼을 none으로 안보이게 하고 숨겨졌던 수정버튼을 block 처리하여 보이게 합니다.

수정 버튼 클릭시 ajax로 수정을 처리합니다.
삭제도 마찬가지로 ajax로 삭제를 처리합니다.

수정 결과

0개의 댓글