쌍용교육(JAVA)/SpringBoot

쌍용교육 -JSP수업 96일차 ch15SpringPage(7)

구 승 2024. 7. 3. 14:06

좋아요 숫자 표시하기

BoardMapper.xml

84라인에 내용추가

LEFT OUTER JOIN (SELECT COUNT (*) fav_cnt, board_num FROM spboard_fav GROUP BY board_num) USING(board_num) <!-- fav_cnt는 알리아스 명칭임 이 괄호는 인라인 뷰 -->

댓글 만들기

table.sql

--댓글
create table spboard_reply(
 	re_num number not null,
 	re_content varchar2(900) not null,
 	re_date date default sysdate not null,
 	re_mdate date,
 	re_ip varchar2(40) not null,
 	board_num number not null,
 	mem_num number not null,
 	constraint spboard_reply_pk primary key (re_num),
 	constraint reply_spboard_fk1 foreign key (board_num)
 							references spboard (board_num),
 	constraint reply_spmember_fk2 foreign key (mem_num)
 							references spmember (mem_num)
 	
);
create sequence spreply_seq;

kr.spring.board.vo =>BoardReplyVO

package kr.spring.board.vo;


import kr.spring.util.DurationFromNow;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class BoardReplyVO {
	private long re_num;		//댓글번호
	private String re_content;	//내용
	private String re_date;		//등록일
	private String re_mdate;	//수정일
	private String re_ip;		//아이피 주소
	private long board_num;		//부모글 번호
	private long mem_num;		//작성자 회원번호
	
	private String id;			//아이디(조인의 의해서 만들어질것)
	private String nick_name;	//별명(조인의 의해서 만들어질것)
	
	//로그인 한 상태에서 클릭한 사람의 정보 읽기, 로그인하지 않으면 0 전달
	private int click_num;
	private int refave_cnt;		//댓글 좋아요 갯수
	
	private int resp_cnt;		//답글 개수 
	
	//댓글 날짜를 하루전 한달전 등으로 바꿔주는 코드를 연결하는법
	public void setRe_date(String re_date) {
		this.re_date = DurationFromNow.getTimeDiffLabel(re_date);
		
	}
	public void setRe_mdate(String re_mdate) {
		this.re_date = DurationFromNow.getTimeDiffLabel(re_mdate);
		
	}
}

DurationFromNow.java
0.00MB

kr.spring.util에 이 파일을 넣는다. 댓글을 달았을 때 날짜를 명시하는것이 아닌 하루전 한달 전 등으로 명시하도록 해주는 코드

 

BoardMapper.java

//댓글
	public List<BoardReplyVO> selectListReply(Map<String,Object> map);
	public Integer selectRowCountReply(Map<String,Object>map); //mybatis는 객체형태로 처리하기 때문에 int보다 Integer로 명시한다. int를 써도 자동으로 바뀌긴함. 그냥 명시를 맞게 해주는게 좋아서 
	public BoardReplyVO selectReply(Long re_num);
	public void insertReply(BoardReplyVO boardReply);
	public void updateReply(BoardReplyVO boardReply);
	public void deleteReply(Long re_num);
	//부모글 삭제시 댓글이 존재하면 부모글 삭제전 댓글 삭제
	public void deleteReplyByBoardNum(Long board_num);
	//부모글 삭제시 댓글의 답글이 존재하면 댓글 번호를 구해서 답글 삭제시 사용
	public List<Long> selectReNumsByBoard_num(Long board_num);

BoardService.java

//댓글
	public List<BoardReplyVO> selectListReply(Map<String,Object> map);
	public Integer selectRowCountReply(Map<String,Object>map); //mybatis는 객체형태로 처리하기 때문에 int보다 Integer로 명시한다. int를 써도 자동으로 바뀌긴함. 그냥 명시를 맞게 해주는게 좋아서 
	public BoardReplyVO selectReply(Long re_num);
	public void insertReply(BoardReplyVO boardReply);
	public void updateReply(BoardReplyVO boardReply);
	public void deleteReply(Long re_num);

아래 2개 public은 넣지않는다. service는 조합하는 것이기 떄문에

BoardserviceImpl에서 add클릭해서 내용 추가

BoardserviceImpl 

그외 코드 추가명시

//댓글 삭제
		boardMapper.deleteReplyByBoardNum(board_num);

BoardMapper.xml

<!-- 댓글 등록 -->
	<insert id="insertReply" parameterType="boardReplyVO">
		INSERT INTO spboard_reply(
			re_num,
			re_content,
			re_ip,
			board_num,
			mem_num)
		VALUES(
			spreply_seq.nextval,
			#{re_content},
			#{re_ip},
			#{board_num},
			#{mem_num})
	</insert>

BoardServiceImpl

@Override
	public void insertReply(BoardReplyVO boardReply) {
		boardMapper.insertReply(boardReply);
		
	}

BoardAjaxController

/*===================
		댓글 등록
	===================*/
	@PostMapping("/board/writeReply")
	@ResponseBody
	public Map<String,String> writeReply(BoardReplyVO boardReplyVO,
										 HttpSession session,
										 HttpServletRequest request){
		log.debug("<<댓글 등록>> :"+boardReplyVO);
		
		Map<String,String> mapJson = new HashMap<String, String>();
		
		MemberVO user = (MemberVO)session.getAttribute("user");
		if(user == null) {
			//로그인 안된경우
			mapJson.put("result","logout");
		}else {
			//회원번호 저장
			boardReplyVO.setMem_num(user.getMem_num());
			//ip등록
			boardReplyVO.setRe_ip(request.getRemoteAddr());
			//댓글 등록
			boardService.insertReply(boardReplyVO);
			mapJson.put("result","success");
		}
		
		
		return mapJson;
	}

board.reply.js

$(function(){
	let rowCount = 10;
	let currentPage;
	let count;
	
	/*===================
		댓글 목록
	===================*/
	//댓글 목록
	function selectList(pageNum){
		
	}
	/*===================
		댓글 등록
	===================*/
	//댓글 등록
	$('#re_form').submit(function(event){
		if($('#re_content').val().trim()==''){
			alert('내용을 입력하세요');
			$('#re_content').val('').focus();
			return false;
		}
		
		let form_data = $(this).serialize();
		console.log(form_data); //alert 창이 아닌 콘솔(console)창으로 띄우고자함.
		
		//서버와 통신
		$.ajax({
			url:'writeReply',
			type:'post',
			data:form_data,
			dataType:'json',
			success:function(param){
				if(param.result == 'logout'){
					alert('로그인해야 작성할 수 있습니다.');
				}else if(param.result == 'success'){
					//폼 초기화
					initForm();
					//댓글 작성시 성공하면 새로 삽입한 글을 포함해서 
					//첫번째 페이지의 게시글들을 다시 호출함
					selectList(1);
				}else{
				    alert('댓글 등록 오류 발생')	
				}
			},
			error:function(){
				alert('네트워크 오류 발생');
			}
		});
		
		//폼 기본 이벤트 제거 (submit하지 않게 하려고)
		event.preventDefault();
		
		
	});
	//댓글 작성 폼 초기화
	function initForm(){
		$('textarea').val('');
		$('#re_first .letter-count').text('300/300');
	}
	/*===================
		댓글 수정
	===================*/
	
	/*===================
		댓글(답글) 등록, 수정 공통
	===================*/
	
	/*===================
		댓글 삭제
	===================*/
	
	/*===================
		댓글수 표시
	===================*/
	/*===================
		댓글수 좋아요 등록
	===================*/
	/*===================
		댓글수 좋아요 표시
	===================*/
	/*===================
		답글 등록
	===================*/
	/*===================
		답글 목록
	===================*/
	
	/*===================
		답글 수정
	===================*/
	
	/*===================
		답글 삭제
	===================*/
	
	/*===================
		초기 데이터 호출
	===================*/
	selectList(1);
});

boardView.jsp

<script src="${pageContext.request.contextPath}/js/board.reply.js"></script>
<!-- 댓글 목록 출력 -->
	<div id="output"></div>
	<div id="loading" style="display:none;">
		<img src="${pageContext.request.contextPath}/images/loading.gif" width="30" height="30">
	</div>
	<div class="paging-button" style="display:none;">
		<input type="button" value="더보기">
	</div>

asd라고 쓰고 테스트겸 보내본다.
값이 잘 들어가짐

board.reply.js

/*===================
		댓글(답글) 등록, 수정 공통
	===================*/
	//textarea에 내용 입력시 글자수 체크
	$(document).on('keyup','textarea',function(){
		//입력한 글자수 구하기
		let inputLength = $(this).val().length;
		
		if(inputLength>300){//300자를 넘어선 경우
			$(this).val($(this).val().substring(0,300));
		}else{//300자 이하인경우
			//남은 글자수 구하기
			let remain = 300 - inputLength;
			remain +='/300';
			if($(this).attr('id')=='re_content'){
				//댓글 등록 폼 글자수
				$('#re_first .letter-count').text(remain);
			}else if($(this).attr('id')=='mre_content'){
				//댓글 수정 폼 글자수
				$('#mre_first .letter-count').text(remain);
			}else if($(this).attr('id')=='resp_content'){
				//답글 등록 폼 글자수
				$('#resp_first .letter-count').text(remain);
			}else{
				//답글 수정 폼 글자수
				$('#mresp_first .letter-count').text(remain);
			}
		}
	});

댓글의 글자수가 바로바로 업데이트됨.

board.reply.js 내용추가

/*===================
		댓글 목록
	===================*/
	//댓글 목록
	function selectList(pageNum){
		currentPage = pageNum;
		
		//서버와 통신
		$.ajax({
			url:'listReply',
			type:'get',
			data:{board_num:$('#board_num').val(),
					pageNum:pageNum,rowCount:rowCount},
			dataType:'json',
			beforeSend:function(){ //통신하기전에 라는 뜻
				$('#loading').show(); //로딩이미지 표시
			},
			complete:function(){ //완료된 후 즉,success나error가 동작된 후에 나오는것
				$('#loading').hide();//로딩이미지 숨김
			},
			success:function(param){
				count = param.count;
				
				if(pageNum ==1){
					$('#output').empty();
				}
				
				//댓글 수 읽어오기
				displayReplyCount(param);
				
				//댓글 목록 작업
				$(param.list).each(function(index,item){
					let output = '<div class="item">';
					output += '<ul class="detail-info">';
					output += '<li>';
					output += '<img src="../member/viewProfile?mem_num="'+item.mem_num+'" width="40" height="40" class="my-photo">';
					output += '</li>';
					output += '<li>';
					
					
					
					
					if(item.nick_name){
						output += item.nick_name + '<br>';
					}else{
						output += item.id + '<br>';
					}
					
					if(item.re_mdate){
						output += '<span class="modify-date">최근 수정일 : ' +item.re_mdate +'</span>';
					}else{
						output += '<span class="modify-date">등록일 : ' +item.re_date +'</span>';
					}
					
					output += '</li>';
					output += '</ul>';
					output += '<div class="sub-item">';
					output += '<p>'+item.re_content.replace(/\r\n/g,'<br>')+'</p>';
					
					//좋아요 시작
					
					//좋아요 끝
					
					if(param.user_num == item.mem_num){
						//로그인 한 회원번호와 댓글 작성자 회원번호가 같으면
						output +=' <input type="button" data-num="'+item.re_num+'" value="수정" class="modify-btn">';
						output +=' <input type="button" data-num="'+item.re_num+'" value="삭제" class="delete-btn">';
					}
					
					//답글 시작
					
					//답글 끝
					output +=  '</div>';
					output +=  '</div>';
					
					//문서 객체에 output 추가
					$('#output').append(output);
					
				}); //end of each
				
				//paging button 처리
				if(currentPage >= Math.ceil(count/rowCount)){
					//다음 페이지가 없음
					$('.paging-button').hide();
				}else{
					//다음 페이지가 존재
					$('.paging-button').show();
				}
				
			},
			error:function(){
				alert('네트워크 오류 발생');
			}
		});
	}

 

BoardMapper.java

sql을 명시해야지 js와 연동되어 작동된다.

	@Select("SELECT COUNT(*) FROM spboard_reply WHERE board_num =#{board_num}")
	public Integer selectRowCountReply(Map<String,Object>map);

 

BoardMapper.xml

sql을 명시해야지 js와 연동되어 작동된다.

<!-- 댓글 목록 -->
	<select id="selectListReply" parameterType="map" resultType="boardReplyVO">
		SELECT
			*
		FROM (SELECT
				a.*,
				rownum rnum
			  FROM (SELECT
			  		  *
			  		FROM spboard_reply
			  		JOIN spmember USING(mem_num)
			  		WHERE board_num=#{board_num}
			  		ORDER BY re_num DESC)a)
		<![CDATA[
		WHERE rnum >=#{start} AND rnum <=#{end}
		]]>
	</select>

BoardServiceImpl

@Override
	public List<BoardReplyVO> selectListReply(Map<String, Object> map) {
		return boardMapper.selectListReply(map);
	}

	@Override
	public Integer selectRowCountReply(Map<String, Object> map) {
		return boardMapper.selectRowCountReply(map);
	}

BoardAjaxController

/*===================
		댓글 목록
	===================*/
	@GetMapping("/board/listReply")
	@ResponseBody
	public Map<String,Object> getList(int board_num, int pageNum, 
										int rowCount, HttpSession session){
		log.debug("<<댓글 목록 - board_num>> : "+board_num);
		log.debug("<<댓글 목록 - page_num>> : "+pageNum);
		log.debug("<<댓글 목록 - rowCount>> : "+rowCount);
		
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("board_num",board_num);
		
		//총글의 개수
		int count = boardService.selectRowCountReply(map);
		
		//페이지 처리
		PagingUtil page = new PagingUtil(pageNum, count, rowCount); //start row_num과 end row_num 번호를 알아서 연산해줌
		map.put("start",page.getStartRow());
		map.put("end",page.getEndRow());
		
		MemberVO user = (MemberVO)session.getAttribute("user");
		if(user!=null) {
			map.put("mem_num",user.getMem_num());
		}else {
			map.put("mem_num",0);
		}
		
		List<BoardReplyVO> list = null;
		
		if(count > 0) {
			list = boardService.selectListReply(map);
		}else {
			list = Collections.emptyList(); //null보단 비어있는 리스트로 인식하게 한다.
		}
		
		Map<String,Object> mapJson = new HashMap<String, Object>();
		mapJson.put("count",count);
		mapJson.put("list",list);
		if(user!=null) {
			mapJson.put("user_num",user.getMem_num());
		}
		
		return mapJson;
	}

이미지가 깨진 것 외에 문제없음

board.reply.js

mem_num다음  "가 하나 더있었음 . 아래는 수정한 코드다.

output += '<img src="../member/viewProfile?mem_num='+item.mem_num+'" width="40" height="40" class="my-photo">';

프로필 사진 잘나오는 모습
비회원이면 수정/삭제가 불가능한 모습
다른 아이디 역시 수정/삭제가 보이질않음

2024/07/03
>>SQL 테이블 및 시퀀스 만들기
>>VO에 sql입력한 것들 저장 및 조인할 값들, 날짜설정 등
>>BoardMapper에 댓글 부분 명시
>>BoardService와 Impl에 작성한것 명시
>>BoardServiceImple 추가명시
>>BoardMapper.xml에 sql명시
>>BoardServiceImpl에 sql 명시한 것을 연동
>>BoardAjaxController에 PostMapping 하여 회원번호를 저장하고 ip와 댓글을 등록함
>>board.reply.js에 댓글목록,등록,수정,삭제,표시,좋아요등록 등등 여러개를 작동시키기 위한 코드 작성
>>boardView.jsp 에서 화면 구현
>>BoardMapper.java와 BoardMapper.xml에서 board.reply.js 추가명시 한 것들(작성,삭제)등을 작동시키기위해 sql명시
>>BoardServiceImpl 에 sql 명시한 걸 연결해준다.
>>BoardAjaxController 에서 연결해준것들을 매핑 후 호출한다.