1.23 (tiles-댓글 수정,삭제,duration / 채팅 테이블 생성)
<복습>
1.
댓글 작업 순서
mapper에서 SQL문 작성 -> controller 에서 호출 -> board.reply.js 에서 ajax 코드 작성
2.
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">';
여기 input 앞에 ('와 < 사이에) 공백을 줬기 때문에 공백이 그대로 생기면서 수정삭제 버튼 사이에 공간이 생김
<댓글 수정폼 생성>
한건의 데이터 읽어오는 메서드 + update 메서드 sql문 작성
BoardMapper.java
//댓글 수정,삭제 시 작성자 회원번호 구할 때 사용
@Select("SELECT * FROM spboard_reply WHERE re_num=#{re_num}")
public BoardReplyVO selectReply(int re_num); //한건의 데이터 읽어오기
@Update("UPDATE spboard_reply SET re_content=#{re_content}, re_ip=#{re_ip}, re_mdate=SYSDATE WHERE re_num=#{re_num}")
public void updateReply(BoardReplyVO boardReply);
1.
작성자 회원번호 구하기 위함
2.
업데이트를 위한 구문
Service파일에서 호출
BoardServiceImpl
@Override
public BoardReplyVO selectReply(int re_num) {
return boardMapper.selectReply(re_num);
}
@Override
public void updateReply(BoardReplyVO boardReply) {
boardMapper.updateReply(boardReply);
}
ajaxController에서 작성
BoardAjaxController
/*=============================
* 댓글 수정
============================*/
@RequestMapping("/board/updateReply")
@ResponseBody
public Map<String,String> modifyReply(BoardReplyVO boardReplyVO,
HttpSession session,
HttpServletRequest request){
log.debug("<<댓글 수정 BoardReplyVO>> : " + boardReplyVO);
Map<String,String> mapJson = new HashMap<String,String>();
return mapJson;
}
jquery로 댓글 수정 폼 생성하기
수정 버튼 클릭 시 기존 content 위치에 폼이 생성되는 방식으로 수행
board.reply.js
/*----------------------
댓글 수정
------------------------*/
//댓글 수정 버튼 클릭 시 수정폼 노출
$(document).on('click','.modify-btn',function(){
//댓글 번호 구하기
let re_num = $(this).attr('data-num');
//댓글 내용 구하기
let content = $(this).parent().find('p').html().replace(/<br>/gi,'\r\n');
//댓글 수정폼 UI 생성
let modifyUI = '<form id="mre_form">';
modifyUI += '<input type="hidden" name="re_num" id="mre_num" value="'+re_num+'">';
modifyUI += '<textarea rows="3" cols="50" name="re_content" id="mre_content" class="rep-content">'+content+'</textarea>';
modifyUI += '<div id="mre_first"><span class="letter-count">300/300</span></div>';
modifyUI += '<div id="mre_second" class="align-right">';
modifyUI += ' <input type="submit" value="수정">';
modifyUI += ' <input type="button" value="취소" class="re-reset">';
modifyUI += '</div>';
modifyUI += '<hr size="1" noshade width="96%">';
modifyUI += '</form>';
//이전에 이미 수정하는 댓글이 있을 경우 수정 버튼을 클릭하면
//숨김 sub-item을 환원시키고, 수정폼을 초기화
initModifyForm();
//지금 클릭해서 수정하고자 하는 데이터는 감추기
//수정 버튼을 감싸고 있는 div를 감추기
$(this).parent().hide();
//수정폼을 수정하고자 하는 데이터가 있는 div에 노출
$(this).parents('.item').append(modifyUI); //sub_item은 숨겨지기 때문에 부모태그에 붙임
//입력한 글자수 셋팅
let inputLength = $('#mre_content').val().length;
let remain = 300 - inputLength;
remain += '/300';
//문서 객체에 반영
$('#mre_first .letter-count').text(remain);
});
//수정폼에서 취소 버튼 클릭 시 수정폼 초기화
$(document).on('click', '.re-reset',function(){
initModifyForm();
});
//댓글 수정폼 초기화
function initModifyForm(){
$('.sub-item').show();
$('#mre_form').remove();
}
1.
$(document).on('click','.modify-btn',function(){});
수정, 삭제버튼이 기존 jsp 파일에 본래 없고 동적으로 js 파일에 만든거라 이벤트를 document로 연결
2.
replace(/<br>/gi,'\r\n');
아까 위에서 줄바꿈을 위해 br태그를 만들었기 때문에 모든 br을 다시 바꾸는 거임
3.
modifyUI += '<input type="hidden" name="re_num" id="mre_num">'
위 댓글 번호 구할때의 id와 중복되지 않게 하려고 m을 붙임 (mre_content, mre_first도 동일한 이유)
class는 겹쳐도 상관x
4.
댓글 창을 여러개 수정시키는걸 막기위해 하나 누른 상태에서 다른걸 또 누르면 처음에 누른 폼을 초기화 시키기 위해 initModifyForm을 만들어서 활용할거임
5.
$(this).parents('.item').append(modifyUI);
수정하고자 하는 데이터가 있는 부모'들'에 붙이기 위해 parents 사용
수정버튼 수정폼 열림!
<댓글 수정기능 구현>
AjaxController 코드 작성
BoardAjaxController
/*=============================
* 댓글 수정
============================*/
@RequestMapping("/board/updateReply")
@ResponseBody
public Map<String,String> modifyReply(BoardReplyVO boardReplyVO,
HttpSession session,
HttpServletRequest request){
log.debug("<<댓글 수정 BoardReplyVO>> : " + boardReplyVO);
Map<String,String> mapJson = new HashMap<String,String>();
MemberVO user = (MemberVO)session.getAttribute("user");
BoardReplyVO db_reply = boardService.selectReply(boardReplyVO.getRe_num());
if(user==null) {
//로그인이 되지 않은 경우
mapJson.put("result", "logout");
}else if (user!=null && user.getMem_num()==db_reply.getMem_num()){
//로그인한 회원번호와 작성자 회원번호가 일치
//ip 등록
boardReplyVO.setRe_ip(request.getRemoteAddr());
//댓글 수정
boardService.updateReply(boardReplyVO);
mapJson.put("result", "success");
}else {
//로그인한 회원번호와 작성자 회원번호가 불일치
mapJson.put("result", "wrongAccess");
}
return mapJson;
}
댓글 수정 js코드 작성
board.reply.js
//댓글 수정
$(document).on('submit','#mre_form',function(event){
if($('#mre_content').val().trim()==''){
alert('내용을 입력하세요');
$('#mre_content').val('').focus();
return false;
}
//폼에 입력한 데이터 반환
let form_data = $(this).serialize();
//서버와 통신
$.ajax({
url:'updateReply',
type:'post',
data:form_data,
dataType:'json',
success:function(param){
if(param.result=='logout'){
alert('로그인해야 수정할 수 있습니다.');
}else if(param.result=='success'){
//내용 읽기
$('#mre_form').parent().find('p').html($('#mre_content').val().replace(/</g,'<').replace(/>/g,'>').replace(/\r\n/g,'<br>').replace(/\r/g,'<br>').replace(/\n/g,'<br>'));
//최근 수정일 처리
$('#mre_form').parent().find('.modify-date').text('최근 수정일 : 5초미만');
//수정폼 초기화
initModifyForm();
}else if(param.result=='wrongAccess'){
alert('타인의 글은 수정할 수 없습니다.');
}else{
alert('댓글 수정 오류');
}
},
error:function(){
alert('네트워크 오류 발생');
}
});
//기본 이벤트 제거
event.preventDefault();
});
1.
$('#mre_form').parent().find('p').html($('#mre_content').val().replace(/</g,'<').replace(/>/g,'>').replace(/\r\n/g,'<br>').replace(/\r/g,'<br>').replace(/\n/g,'<br>'));
p태그를 찾아서 변경할 내용을 그 안에 html로 셋팅
서버에 저장 후 읽어오는 게 아니라 화면에 입력 후 읽어오는거기 때문에 html 불허 처리를 해야함
댓글 수정하는 방법 (정리)
1. db에 보내고 select해서 한건 읽어온 후 그걸 화면 출력 (저장했던 데이터 다시 읽어오는 방법)
2. db access로 굳이 안받아오고 그냥 화면갱신으로 불러오기
이렇게 2가지 방법이 있는데 2번이 덜 번거롭고 좋다고 하심
<댓글 삭제기능 구현>
삭제 sql문 작성
BoardMapper.java
@Delete("DELETE FROM spboard_reply WHERE re_num=#{re_num}")
public void deleteReply(int re_num);
Service에서 호출
BoardServiceImpl
@Override
public void deleteReply(int re_num) {
boardMapper.deleteReply(re_num);
}
Controller 작성
BoardAjaxController
/*=============================
* 댓글 삭제
============================*/
@RequestMapping("/board/deleteReply")
@ResponseBody
public Map<String,String> deleteReply(@RequestParam int re_num,
HttpSession session){
log.debug("<<댓글 삭제 re_num>> : " + re_num);
Map<String,String> mapJson = new HashMap<String,String>();
MemberVO user = (MemberVO)session.getAttribute("user");
BoardReplyVO db_reply = boardService.selectReply(re_num);
if(user==null) {
//로그인이 되지 않은 경우
mapJson.put("result", "logout");
}else if(user!=null && user.getMem_num()==db_reply.getMem_num()) {
//로그인한 회원번호와 작성자 회원번호가 일치
boardService.deleteReply(re_num);
mapJson.put("result", "success");
}else {
//로그인한 회원번호와 작성자 회원번호가 불일치
mapJson.put("result", "wrongAccess");
}
return mapJson;
}
js 작성
board.reply.js
/*----------------------
댓글 삭제
------------------------*/
$(document).on('click','.delete-btn',function(){
//댓글 번호 구하기
let re_num = $(this).attr('data-num');
//서버와 통신
$.ajax({
url:'deleteReply',
type:'post',
data:{re_num:re_num},
dataType:'json',
success:function(param){
if(param.result=='logout'){
alert('로그인해야 삭제할 수 있습니다.');
}else if(param.result=='success'){
alert('삭제 완료!');
selectList(1);
}else if(param.result=='wrongAccess'){
alert('타인의 글을 삭제할 수 없습니다.');
}else{
alert('댓글 삭제 오류 발생');
}
},
error:function(){
alert('네트워크 오류 발생!')
}
});
});
1.
data:{re_num:re_num},
앞 re_num=key 뒤 re_num=value
뒤 re_num은 위에서 명시한 변수임
2.
selectList(1);
첫 페이지 호출
==============================
restart 후 누르면 삭제+alert창 뜸
<추가기능-Duration 처리>
mbox에서 duration 클래스 내려받고 kr.spring.util에 복붙
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 int re_num;
private String re_content;
private String re_date;
private String re_mdate; //연월일시분초가 아니라 하루전 이틀전 이렇게 변환 작업할거라서 string 처리
private String re_ip;
private int board_num;
private int mem_num;
private String id;
private String nick_name;
//작성
public void setRe_date(String re_date) {
this.re_date = DurationFromNow.getTimeDiffLabel(re_date);
}
//수정
public void setRe_mdate(String re_mdate) {
this.re_mdate = DurationFromNow.getTimeDiffLabel(re_mdate);
}
}
restart 후
최근 수정일 : 14초 전
이런식으로 시간이 바껴서 나옴
==============================
<깨알 정리>
부모글에 자식글이 있을 시에는 특히 주의해야함
ServiceImpl 안 메서드를 보면
@Override
public void deleteBoard(int board_num) {
//부모글 좋아요 삭제
boardMapper.deleteFavByBoardNum(board_num);
//댓글이 존재하면 댓글을 우선 삭제하고 부모글 삭제
boardMapper.deleteReplyByBoardNum(board_num);
//부모글 삭제
boardMapper.deleteBoard(board_num);
}
이런식으로 다 처리를 해놓음
게시판 끝
<채팅 시작>
그룹채팅
id검색 시 초대해서 그룹으로 채팅하는 형식
nickname반영 X id중심으로 진행
테이블 생성
sql
table.sql
--채팅방
create table sptalkroom(
talkroom_num number not null,
basic_name varchar2(900) not null, --기본 채팅방 이름
talkroom_date date default SYSDATE not null,
constraint sptalkroom_pk primary key (talkroom_num)
);
create sequence sptalkroom_seq;
--채팅방 멤버 (구성원)
create table sptalk_member(
talkroom_num number not null,
mem_num number not null,
room_name varchar2(900) not null, --멤버별 채팅방 이름 (방 이름 변경 시 roon_name 사용)
member_date date default SYSDATE not null,
constraint sptalk_member_fk1 foreign key (talkroom_num) references sptalkroom (talkroom_num),
constraint sptalk_member_fk2 foreign key (mem_num) references spmember (mem_num)
);
--채팅(메시지) 테이블
create table sptalk(
talk_num number not null,
talkroom_num number not null, --메시지 받는 수신 그룹
mem_num number not null, --발신자
message varchar2(4000) not null,
chat_date date default SYSDATE not null,
constraint sptalk_pk primary key (talk_num),
constraint sptalk_fk1 foreign key (talkroom_num) references sptalkroom (talkroom_num),
constraint sptalk_fk2 foreign key (mem_num) references spmember (mem_num)
);
create sequence sptalk_seq;
--채팅 메시지 확인 (읽었는지 안 읽었는지 체크하는 테이블)
create table sptalk_read(
talkroom_num number,
talk_num number not null,
mem_num number not null,
constraint read_fk1 foreign key (talkroom_num) references sptalkroom (talkroom_num),
constraint read_fk2 foreign key (talk_num) references sptalk (talk_num),
constraint read_fk3 foreign key (mem_num) references spmember (mem_num)
);
sptalk_read
여러명에 대해 읽었는지 안읽었는지 체크하려면 테이블이 별도로 필요함