[TIL] Day41 - 댓글

JIONY·2022년 11월 10일
0

TIL - Web BE - Spring Boot

목록 보기
17/20
post-thumbnail

오 테이블 조인 대박 신기함 2월에 SQLD 공부할 때는 느낌만 알 것 같은 그런 상태였는데 역시 백문이불여일견


댓글 구조

  • 특정 대상에 달리는 내부 글
  • 게시판 내부에 작성하는 것이 목표
    • 게시글 하나에 여러 개의 댓글이 달림(o)
    • 여러 게시글에 하나에 댓글이 달림(x)
    • 1:N
  • 별도의 테이블과 시퀀스를 만들고 외래키로 연결
  • 댓글에 영향을 받는 게시판 페이지: 목록, 상세
    - 상세: 댓글 목록/작성 입력/수정 입력/삭제버튼

DB 설계

최소한의 컬럼만으로 구성

  • 대댓글 구현하려면 답글처럼 그룹/차수/상위글 있어야 함

### PK 외래키가 있어도 한 명이 여러 개의 댓글을 작성할 수 있으니까 복합키가 PK 될 수 없고, 수정/삭제 할 때 PK 써야 하므로 reply_no 추가(sequence)

FK

외래키 조건 설정: on delete cascade

  • 글이 사라지면 댓글도 사라짐

Controller, Repository

  • 게시글이 있어야만 댓글이 있을 수 있음
    → BoardController 그대로 사용
  • Repository는 분리
  • 등록
    • 시퀀스 번호 미리 안뽑아도 됨. 상세로 갈 일이 없기 때문
    • 내용, 원본글 번호를 보내야 함: form에 name이 두 개여야 함
  • 조회
    • 특정 글에 대한 댓글을 조회하도록 구현
    • 댓글은 일반적으로 작성순으로 나옴
  • 삭제
    • 댓글 번호로 삭제할 댓글 지정, 원본글 번호 넘겨서 detail로 돌아와야 함

테이블 생성

컬럼명에 comment대신 reply를 사용함

create sequence reply_seq;
create table reply(
reply_no number primary key,
reply_writer varchar2(20) 
references member(member_id) on delete set null,
reply_origin number 
references board(board_no) on delete cascade,
reply_writetime date default sysdate not null,
reply_updatetime date,
reply_content varchar2(3000) not null
);

View

목록 조회

  • 게시글 작성자가 댓글을 등록했을 때 (작성자) 표시
  • 댓글 내용에 pre태그 추가
  • 댓글은 페이징 방식보다는 프론트에서 더보기 방식으로 처리하는 경우가 많음
    • 차수: 들여쓰기를 많이 하면 모바일에서 보기 힘들기 때문에 폭 조정을 안하는 방식으로 바뀜

등록

  • form: 현재 테이블 안에 input이 있음. form은 테이블 전체를 감싸거나, 테이블 내 td 하나에만 쓸 수 있음. 입력창과 버튼을 다른 td에 만들면 전송이 안되고, 전체에 씌우면 수정이 안됨
    → 목록 테이블에서 분리해서 새 테이블로 만들거나 테이블을 사용하지 않기
  • 원본글 번호 넘겨야 함
    <input type="hidden" name="replyOrigin" value="${dto.boardNo}">
  • 비회원일 때 댓글 입력창 다르게 나와야 함
    • disabled(입력/전송 모두 비활성화)
    • 조작의 여지를 없애고 싶으면 form을 로그인했을 때만 보이게 하기
    • 비회원일 때는 textarea만 보이게 하기
      or textarea만 비활성화 시키기
      → textarea와 button 둘다 수정해야 함

수정

  • 댓글 목록에서 [수정][취소] 버튼 클릭 시에는 서버를 안탐(프론트)
    • [수정] 클릭 시 입력 가능한 상태로 바뀌는데, ‘바뀜’이 아니라 목록과 수정 화면 ‘두 개 중 하나’를 보여준다고 생각해야 함
      -> js / jQuery 학습 후에 구현 가능
  • 다른 사람 수정용 화면 안보이게 하기
    - 댓글 작성자만 수정 가능
  • 댓글 번호, 내용, 원본글 번호 전달

삭제

  • 댓글 번호로 삭제
  • 댓글 작성자만 삭제 가능

Controller

목록 조회

  • 게시글 상세 매핑에 목록 조회 결과를 모델로 첨부

등록

  • 댓글은 PostMapping만 있음(입력이 다른 페이지에 있으니까)

수정

  • redirect 주소 : 삭제와 동일

삭제

  • 삭제하려는 댓글을 댓글 번호로 조회했을 때 없을 수 있음
    • RequestParam은 없으면 error인데, ModelAttribute는 없으면 0들어감 → RequestParam 권장

Interceptor

댓글 작성자 체크

  • 댓글 작성자만 + 게시글 상세 페이지에서만 수정/삭제 가능하도록 처리
  • 개발자 도구의 network > headers > referer에서 직전 페이지 확인 가능
    • 직접 주소로 들어오면 referer == null

댓글 블라인드 처리

테이블 변경

  • DB마다 제공 자료형이 다르지만 BOOLEAN은 없을 수 있음
    • 숫자 문자 날짜는 다 있음
  • 댓글 테이블에 상태 컬럼 추가
    • null or Y : not null이 아니라서 기존 댓글 모두 null 처리되므로 추가 처리 불필요
    alter table reply add reply_blind char(1) check(reply_blind='Y')



DTO 변경

private boolean replyBlind; //자바에서는 boolean으로 선언
  • boolean은 자동 생성 시 getter()가 is로 시작함(ex.isReplyBlind())
    • ${replyDto.replyBlind} 값을 댓글 목록 화면에서 확인해보니 null인 경우 false로 나와서 수정 사항 없이 그대로 진행

DaoImpl 변경

mapper, extractor 변경

replyDto.setReplyBlind(rs.getString("reply_blind")!=null);
//char를 boolean으로 받기 때문에 

DaoImpl insert()

default는 지정하지 않으면 null이기 때문에 insert 구문에 문제 없음


updateBlind()추가

  • 삼항 연산: boolean을 DB에 그대로 넣을 수 없으니 converter 만들어야 함
    • String replyBlind = blind ? "Y" : null; (blind면 "Y", 아니면 null)
    • 단항 연산 ex. !
    • 이항 연산 ex. 더하기
    • 삼항 연산 : 연산에 값이 세 개 필요
@Override
public boolean updateBlind(int replyNo, boolean blind) {
	String sql = "update reply "
				+ "set reply_blind = ? "
				+ "where reply_no = ?";
	String replyBlind = blind ? "Y" : null;
	Object[] param = {replyBlind, replyNo};
		
	return jdbcTemplate.update(sql, param) > 0;
}

View

detail.jsp

  • 관리자 블라인드 메뉴 구현
    • 블라인드 설정 / 블라인드 해제
    • 댓글 번호, 원본 글 번호(redirect:detail) 전달
    • <a href="reply/blind?replyNo=${replyDto.replyNo}&replyOrigin=${replyDto.replyOrigin}">
    • *링크 중간에 줄바꿈 불가
  • 블라인드 처리
    • replyContent를 변경

Controller

  • /reply/blind[GET]
@GetMapping("/reply/blind")
public String replyBlind(@RequestParam int replyNo,
			@RequestParam int replyOrigin,
			RedirectAttributes attr) {
	ReplyDto replyDto = replyDao.selectOne(replyNo);
	replyDao.updateBlind(replyNo, !replyDto.isReplyBlind());
	attr.addAttribute("boardNo", replyOrigin);
	return "redirect:/board/detail";		
}

adminInterceptor

  • 댓글 블라인드 주소 추가
    • 관리자만 블라인드 처리 가능



테이블 조인

inner join

  • 연결 데이터끼리만 조회

outer join

  • 연결이 안 된 데이터도 조회해줌
    • 없는 쪽은 null로 나옴
  • 방향이 있음
    • 한쪽 테이블을 기준으로 설정하여 다른 테이블을 합치는 형태

강사님이 inner join은 커플 조회, outer join은 솔로 조회라고 쉽게 예를 들어주셨는데 빡 와닿아서 그 느낌을 계속 가져가고 있음 ㅋㅋㅋ


댓글-회원 조인

  • 댓글 목록에 회원 테이블에만 있는 정보를 붙여서 같이 조회할 수 있음
    • ex. 댓글 테이블에는 작성자에 대한 정보가 id만 있는데, 닉네임이나 등급을 댓글 목록에 함께 보여줄 수 있음

댓글에 닉네임/등급 출력

  • 회원은 탈퇴를 할 수 있으므로 댓글 기준 left outer join 사용
select
    R.*,
    M.member_nick, M.member_grade
from reply R left outer join member M on R.reply_writer=M.member_id;

게시글-댓글 조인

  • 게시글 목록에 댓글 개수를 함께 조회하려면 두 가지 방법을 사용할 수 있음
    • 이 때, 와일드카드(*)를 사용하면 null도 count해서 count(*)의 결과가 1로 나오므로 조회할 컬럼을 지정해야 함

1. GROUP BY 사용

  • select절의 컬럼과 group by절의 컬럼이 같아야 함
select
    B.board_no, B.board_head, 
    B.board_title, B.board_content, 
    B.board_writer, B.board_writetime, B.board_read,
    B.board_like, B.board_group, 
    B.board_parent, B.board_depth, 
    count(R.reply_no) reply_count
from board B 
	left outer join reply R 
    on B.board_no=R.reply_origin
group by  
	B.board_no, B.board_head, 
    B.board_title, B.board_content, 
    B.board_writer, B.board_writetime, 
    B.board_read, B.board_like, 
    B.board_group, B.board_parent, B.board_depth
order by B.board_no desc;

2. 분석함수 over() 사용

  • over()는 결과를 행에 붙여줌→ 중복 제거
  • select에 * 사용 가능, count에 별칭 부여
select distinct
    B.*, 
    count(R.reply_no) 
    	over(partition by B.board_no) reply_count
from board B 
	left outer join reply R 
    on B.board_no = R.reply_origin;

화면에 출력

  • VO를 생성하고, RowMapper를 추가/수정한 후 jsp에 출력할 내용을 추가

0개의 댓글