좋아요 숫자 표시하기
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);
}
}
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>
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 에서 연결해준것들을 매핑 후 호출한다.
'쌍용교육(JAVA) > SpringBoot' 카테고리의 다른 글
쌍용교육 -JSP수업 98일차 ch15SpringPage(9) (0) | 2024.07.05 |
---|---|
쌍용교육 -JSP수업 97일차 ch15SpringPage(8) (0) | 2024.07.04 |
쌍용교육 -JSP수업 94일차 ch15SpringPage(5) (0) | 2024.07.01 |
쌍용교육 -JSP수업 93일차 ch15SpringPage(4) (0) | 2024.06.28 |
쌍용교육 -JSP수업 92일차 ch15SpringPage(3) (1) | 2024.06.27 |