본문 바로가기

국비과정/Spring

20230804 _[45일차]_01. jquery + json 으로 board2 댓글창 구현

https://staruml.io/

 

StarUML

UML 2 Compatible with UML 2.x standard metamodel and diagrams: Class, Object, Use Case, Component, Deployment, Composite Structure, Sequence, Communication, Statechart, Activity, Timing, Interaction Overflow, Information Flow and Profile Diagram. SYSML SUP

staruml.io

DB 관계도 정리할 수 있다. 다운로드 받기

 

 

File - New Form Template - Data Model

 

Entity 눌러서 빈공간 클릭하면 테이블 생성가능

우측에서 데이터타입, 기본키 등 지정가능

 

하이디에서 만들었던 테이블 그대로 만들어줬다.

기본기, 외래키, 유니크 지정

DATE_ 날짜&시간 

TIMESTAMP _ DATE보다 정밀한 시간

 

테이블 전부 생성해주고 관계 연결해주기

 

PDF 파일로 저장해둠


코멘트 달때 m_no 와 bno가 없으면 댓글을 못쓰게 설정

아래처럼 데이터(댓글) 추가해보면 

아래쪽에 쿼리문이 실행되는데

 

요걸 그대로 따와서 쿼리문을 작성하면 된다.

 

INSERT INTO `c23b_24`.`comment` (`c_no`, `m_no`, `bno`, `c_comment`, `c_date`) 

VALUES (2, 1, 710, '댓글댓글', '2023-08-04 09:48:51');

 

쿼리문으로 댓글데이터가 잘 불러와지는지 확인 

 

테이블 이름 comments로 바꿔줌

저장해주면 아래 쿼리문 뜨는데 이런걸 잘 활용하자

comments를 c로 쓰겠다고 해주면 c로 축약해서 사용가능


* JOIN

 

SELECT c.*, m.m_id, m.m_name
FROM comments c left JOIN members m
ON c.m_no = m.m_no

 

 

SELECT c.*, m.m_id, m.m_name
FROM members m LEFT JOIN comments c
ON c.m_no = m.m_no

 

left JOIN 은 왼쪽에 있는 member테이블을 일단 전부 가져온다.

그 중에 조건에 해당하는 comments테이블의 데이터를 보여준다.

그래서 댓글 안쓴 member들도 가져오지만 댓글을 쓴적이 없으니 comments 테이블 영역은 null값으로 표시된다.

SELECT c.*, m.m_id, m.m_name
FROM members m right JOIN comments c
ON c.m_no = m.m_no


이제 commentsview를 만들자

 

CREATE VIEW commentsview as
SELECT c.c_no, c.m_no, c.bno, m.m_id, m.m_name,
              c.c_comment, c.c_date 
FROM members m JOIN comments c
ON c.m_no = m.m_no

 

아래 쿼리문을 boardview에 넣어줄 예정

 

 

일단 boardview에 있는 쿼리문 찍어서 데이터 불러와지는지 확인해보고

 

아래처럼 해주면 글 10개만 뽑아서 각 글의 comment 갯수를 가져온다.

즉, comments 의 bno랑 board의 bno 가 같은 댓글의 갯수를

commentcount 라는 이름으로 가져온다.

select `b`.`bno` AS `bno`,`b`.`btitle` AS `btitle`,`b`.`bcontent` AS `bcontent`,`m`.`m_name` AS `m_name`,`m`.`m_id` AS `m_id`,if(date_format(current_timestamp(),'%Y-%m-%d') = date_format(`b`.`bdate`,'%Y-%m-%d'),date_format(`b`.`bdate`,'%H:%i:%s'),date_format(`b`.`bdate`,'%Y-%m-%d')) AS `bdate`,`b`.`blike` AS `blike`,`b`.`bip` AS `bip`,(select count(0) from `comments` where `comments`.`bno` = `b`.`bno`) AS `commentcount` 

from (`board` `b` join `members` `m` on(`b`.`m_no` = `m`.`m_no`)) order by `b`.`bno` desc

limit 0, 10;

 

 

위에꺼를 보드뷰에 넣고 저장하면

그러면 아래 boardview에 commentcount가 추가된다.

 


BoardDTO 에 commentcount 변수추가 & getter / setter 생성

 

[ board.jsp ]

db에서 가져온 commentcount를 title 뒤에 붙여보자

 

글제목 뒤에 댓글수가 보인다.

 

근데 댓글수가 0이면 안뜨게 만들어주자 + 댓글숫자도 작게 만들어줬다. small 태그로

 

 css 스타일지정해주자


글을 눌렀을 때 로직은 detail 파트니 여기에서 잡아줄거다.

commentcount도 db에서 가져와 result에 잘 담겼는지 출력해보자.

 

글을 클릭했을 때 댓글수가 콘솔창에 잘 출력된다.

mapper에서 글 불러오는 쿼리문 작성할때 *로 전부 가져왔었다. 

보드뷰에 commentcount도 넣어줬었으니 잘 가져온다.


댓글이 여러개일 수 있으니 list에 담아서 가져와야한다.

조건문으로 댓글이 있을때만 (commentcount가 0보다 클때만) 서비스에게 일을 시킨다.

commentList () 메소드로 bno를 매개변수로 해서 list에 담아서 가져올거다.

 

글을 눌렀을 때 댓글이 하나라도 있다면,  해당 글(bno)에 있는 모든 commentList를 뽑아서 가져오라고 db에 시킬예정

서비스에서도 

DAO에서도

mapper에서 쿼리문 작성

bno를 매개변수로 보내서 Map으로 받아올거라서

parameterType은 Integer, resultType은 Map

detail.jsp에서 출력해보자.


detail.jsp에서 함수 사용할거니 fn태그 선언되어있는지 확인하고

조건문걸어서 commentList의 길이가 0보다 크다면 '댓글이 있어요' 문구가 출력되고

아니라면 '댓글이 없어요' 문구가 출력되도록 해준다.

 

 

이제 진짜 댓글을 찍어보자

그러면 이렇게 comments와 함께  뜬다.

<body>
<%@ include file = "menu.jsp" %>
<h1>상세보기</h1>
	<div class= "detail-content">
		<div class="title">${dto.bno }.  ${dto.btitle }
			<c:if test="${sessionScope.mid ne null && sessionScope.mid eq dto.m_id}">
			<div class="upNde">
				<img alt="" src="./img/update.png" onclick="edit()">&nbsp;<img alt="" src="./img/delete.png" onclick="del()">
			</div>	
			</c:if>
		</div>
		<div class="name">${dto.m_name }님</div>
		<div class="content">${dto.bcontent }</div>
		<div class="under-bar">
			<div class="date">${dto.bdate }</div>
			<div class="like">${dto.blike }</div>
		</div>
			<c:choose>
				<c:when test="${fn:length(commentsList) gt 0}">
				<div class="comment">
					<c:forEach items="${commentsList }" var="c">
						<div class="cBox">
							<div class="cName"> ${c.m_name } (${c.m_id })</div>
							<div class="cComment"> ${c.c_comment } 
								<div class="cDate"> ${c.c_date } </div> 
							</div>
						</div>
					</c:forEach>
				</div>
				</c:when>
			</c:choose>
		<div class="ip">${dto.bip }</div>
			
	</div>
	
	
</body>
@charset "UTF-8";

body{
	margin: 0;
	align-items: stretch;
}

.detail-content{
	margin: 0 auto;
	width: 800px;
	height: auto;
	background-color: #FDF5E6;
	padding: 10px;
	border-radius: 20px;
	box-sizing: border-box;
}
.title{
	width: 100%;
	height: 50px;
	line-height:50px;
	font-size: large;
	background-color: #FDCD8C;
	border-radius: 20px;
	padding: 0 20px 0 20px;
	box-sizing:border-box;
}
.under-bar{
	width: 100%;
	height: 40px;
	padding: 20px;
	box-sizing: border-box;
}
.name, .like{
	text-align: right;
	font-weight: bold;
	padding-top: 10px 10px 0 0;
}
.name{
	margin: 10px;
}

.like, .date{
	width: 50%;
	height:20px;
	float: left;
}

 .ip{
	text-align: center;
	padding: 10px 0 10px 0;
	font-weight: lighter;
}

.content{
	width:500px;
	min-height:500px; 
	height: auto;
	padding: 20px;
	box-sizing:border-box;
}
.upNde{
	margin: 0 auto;
	float: right;
}
.cBox{
	width: 100%;
	background-color: #FFEFD5;
	height: 80px;
	margin-bottom: 20px;
	border-radius: 20px;
	box-sizing: border-box;
}
.cName{
	margin: auto;
	background-color: #FFDAB9;
	border-top-left-radius:20px;
	border-top-right-radius:20px;
	width: 100%;
	height: 50%;
	
}
.cComment{
	width: 100%;
}
.cDate{
	text-align: right;
}

댓글창 아래처럼 보이게 만들어줬다.


if 조건문으로 아래처럼 만들어줄거다.

로그인     => 댓글쓰는창 보임 

로그아웃 => 댓글쓰는창 안보임

 

(LoginController참고) - 입력id와 일치하는 id가 db에 있으면

session에 mid라는 이름으로 id를,  mname이라는 이름으로 name을 담아줬기 때문에

로그인 상태라면 sessionScope.mid 로 불러온 id값이 null이 아니다.

 

일단 로그인했다면 위처럼 댓글창(form) 이 뜬다.


댓글쓰는창을 여는 버튼도 하나 만들어준다

위에 있는 script 부분에 버튼 클릭했을때 실행될 함수 추가

애초에 댓글쓰는 창은 숨겨놓고 (hide)

댓글창열기 버튼을 누르면

버튼은 사라지고 댓글쓰는 창이 열린다.

   hide / remove 둘다가능            show


이제 입력한 댓글을 db로 가져갈건데 (name="comment"로 가져감)

input창 하나 만들어서 해당 글의 bno를 같이 가져갈거다. (name="bno"로 value값인 dto.bno를 가져감)

 

이제 이 과정을 위해 comment용 패키지를 만든다. (컨트롤러, 서비스, DAO도....)

com.phyho.comment 패키지 생성

컨트롤러 생성

밑줄 마우스 올려서 (create CommentService~) 로 CommentService 클래스 만들어준다.

서비스에서도 같은 방식으로 CommentDAO만들어준다.

DAO에서도 SqlSession 연결해주기. 

 

form을 제출하면(댓글등록)

컨트롤러에서는 데이터(comment랑 bno)들을 Map으로 보낸다.

버튼 타입 일단 submit으로 바꿔주고

 

713번 글에서 댓글쓰고 글쓰기 버튼 누르면

콘솔창에 뜬다.


아래처럼 댓글을 쓰고 글쓰기 버튼을 누르면

해당 글로 돌아온다.


db에서 commentInsert() 실행시켜서 값을 가져올건데 int result에 받을거다. (성공실패검사)

서비스에게 일시키자. 

서비스에서는 DAO 한테 일을 시켜

DAO에서는 sqlSession에게 insert () 로 map을 넣으라고 시킨듯..?

comment-mapper.xml 만들어주고(복붙으로)

아래처럼 이름 맞춰준다.

쿼리문에서 insert 하기위해 bno & comment는 가지고 왔는데 m_no는 안가져옴 (세션에는 id랑 name이 있음)

그래서 서브쿼리문으로 m_no를 가져온다. 

세션 안에는 요렇게 있다.

 

session에서 값을 가져와서 뽑아보쟈

댓글을 쓰고 글쓰기 버튼을 누르면 mid가 잘 뜬다.

이제 이 mid를 "mid"라는 이름으로 map에 넣어준다. .put() 으로

 

로그인을 했다면 (mid가 null이 아니라면) mid를 map에 넣어 그걸 매개변수로 디비까지 가져간 후에

결과값을 int result로 가져온다.

이 result 값도 조건문을 달아서 결과값이 1이라면 진행 (결과값이 1인건 실제로 댓글을 썼다는 의미)

 

 

이제 mapper에서는 서브쿼리문으로 위에서 보냈던 mid와 일치하는 m_id의 m_no를 뽑아낸다.

이걸 bno와 comment와 함께 db에 insert 한다

그러면 댓글이 써보면 db에 insert가 되어서 댓글달기가 된다!

 


디비에서 CASCADE로 설정해주면 

글이 삭제될때 댓글까지 함께 다 삭제된다. (외래키로 연결되어있으니 하위요소까지 같이 날아감.)

일단은 데이터가 아까우니 NO ACTION으로 해준다.


 

c_del 필드 추가

 

commentsview에서 

 

select `c`.`c_no` AS `c_no`,
`c`.`m_no` AS `m_no`,
`c`.`bno` AS `bno`,
`m`.`m_id` AS `m_id`,
`m`.`m_name` AS `m_name`,
`c`.`c_comment` AS `c_comment`,
`c`.`c_date` AS `c_date` from (`members` `m` join `comments` `c` on(`c`.`m_no` = `m`.`m_no`)) where `c`.`c_del` = 1

 


 

bdel 필드 추가

boardview에서 

 

select `b`.`bno` AS `bno`,

`b`.`btitle` AS `btitle`,

`b`.`bcontent` AS `bcontent`,

`m`.`m_name` AS `m_name`,

`m`.`m_id` AS `m_id`,

if(date_format(current_timestamp(),'%Y-%m-%d') = date_format(`b`.`bdate`,'%Y-%m-%d'),

date_format(`b`.`bdate`,'%H:%i:%s'),

date_format(`b`.`bdate`,'%Y-%m-%d')) AS `bdate`,

`b`.`blike` AS `blike`,`b`.`bip` AS `bip`,(select count(0) from `comments` where `comments`.`bno` = `b`.`bno` and `comments`.`c_del` = 1) AS `commentcount` from (`board` `b` join `members` `m` on(`b`.`m_no` = `m`.`m_no`)) order by `b`.`bno` desc

 

 

 

select `b`.`bno` AS `bno`,`b`.`btitle` AS `btitle`,`b`.`bcontent` AS `bcontent`,`m`.`m_name` AS `m_name`,`m`.`m_id` AS `m_id`,if(date_format(current_timestamp(),'%Y-%m-%d') = date_format(`b`.`bdate`,'%Y-%m-%d'),date_format(`b`.`bdate`,'%H:%i:%s'),date_format(`b`.`bdate`,'%Y-%m-%d')) AS `bdate`,`b`.`blike` AS `blike`,`b`.`bip` AS `bip`,(select count(0) from `comments` where `comments`.`bno` = `b`.`bno` and `comments`.`c_del` = 1) AS `commentcount` from (`board` `b` join `members` `m` on(`b`.`m_no` = `m`.`m_no`)) where `b`.`bdel` = 1 order by `b`.`bno` desc

 

 

mapper 에서 delete 파트 쿼리문 수정

 

boardDAO 에서 delete 메소드를 update로 수정해준다


bdel 필드를 처음 추가했을 때 기본값에 1을 안넣었는지 다시 수정해도 작동을 안해서 아예 삭제했다가 다시 만들었다.

 

그러면 이제 글을 삭제했을 때 게시판에서는 안보이지만 db에는 남아있다.

bdel  값이 1인 글들만 게시판에 보여진다.

db에서 확인해보면 bdel 값이 0으로 바껴있다.