본문 바로가기

Java/JSP

07.18 공지사항,질문답변 게시판 구현 (7.14실습파일)

<!-- 요청한 페이지 정보와 한페이지에 보여줄 게시물 개수를 연산하여 게시물 목록 검색 -->

<s:query var="rs" dataSource="java/MySqlDB" startRow="${pm.cri.startRow}"

maxRows="${pm.cri.perPageNum}">

SELECT * FROM notice_board

ORDER BY notice_num DESC

</s:query>

<c:if test="${rs.rowCount > 0}">

<jsp:useBean id="noticeList"

class="java.util.ArrayList"

type="java.util.List<vo.NoticeVO>" />

<c:forEach var="notice" items="${rs.rows}">

<jsp:useBean id="vo" class="vo.NoticeVO" />

<!-- 값채우기 -->

<c:forEach var="c" items="${rs.columnNames}">

<!-- 필드이름과 테이블의 속성 이름이 같아야 이렇게 사용이 가능하다.(다른 속성을 지정해놓고 AS로 별칭정의) -->

<c:set target="${vo}" property="${c}" value="${notice[c]}"/>

</c:forEach>

<c:set var="temp" value="${noticeList.add(vo)}"/>

<c:remove var="vo"/><!-- useBean으로 새로운 객체 생성하도록 삭제해줌 -->

</c:forEach>

</c:if>

필드이름과 테이블의 속성 이름이 같아야 
속성명으로 반복문 돌려서 값 채우는 방법 사용이 가능하다.
(SQL 쿼리문 SELECT에서 이름이 필드명과 다른 속성을 지정해놓고 AS로 별칭정의하는 방법이 있다.)

 

<c:choose>

<c:when test="${!empty noticeList}">

<!-- 게시글 목록 존재 시 -->

<c:forEach var="n" items="${noticeList}">

<tr>

<td>${n.notice_num}</td>

<td>

<a href="<c:url value='/board/notice/notice_detail.jsp'/>?notice_num=${n.notice_num}">

[${n.notice_category}] ${n.notice_title}

</a>

</td>

<td>${n.notice_author}</td>

<td>${n.notice_date}</td>

</tr>

</c:forEach>

</c:when>

<c:otherwise>

<!-- 게시글 목록 미 존재 시 -->

<tr>

<td colspan="4">등록된 게시물이 없습니다.</td>

</tr>

</c:otherwise>

</c:choose>


<a href="<c:url value='/board/notice/notice_detail.jsp'/>?notice_num=${n.notice_num}">
게시글 번호 쿼리 스트링으로 같이 전달

<!-- 요청한 페이지 정보와 한페이지에 보여줄 게시물 개수를 연산하여 게시물 목록 검색 -->

<s:query var="rs" dataSource="java/MySqlDB" startRow="${pm.cri.startRow}"

maxRows="${pm.cri.perPageNum}">

SELECT * FROM notice_board

<c:if test="${!empty param.searchValue}">

<c:choose>

<c:when test="${param.searchType eq 'title'}">

WHERE notice_title LIKE '%${param.searchValue}%'

</c:when>

<c:otherwise>

WHERE notice_content LIKE '%${param.searchValue}%'

</c:otherwise>

</c:choose>

</c:if>

ORDER BY notice_num DESC

</s:query>

게시판에서 게시글 검색 기능 구현(검색기준 추가)

 

<select name="perPageNum" onchange="searchName.submit();">

<c:forEach var="i" begin="10" end="25" step="5">

<option value="${i}"${param.perPageNum eq i?'selected':''}>${i}개씩 보기</option>

</c:forEach>

</select>

 

select - option 태그에서 선택되어있는 항목 보여주기

 

<!-- 공지 검색 및 한번에 보여줄 페이지 개수 선택창 -->

<tr>

<td colspan="4">

<!-- form태그에 name 지정하면 이름값으로 바로 접근 가능 -->

<form name="searchName" action="notice_list.jsp" method="get">

<select name="searchType">

<option value="title"${param.searchType eq 'title'? 'selected':''}>제목</option>

<option value="content"${param.searchType eq 'content'? 'selected':''}>내용</option>

</select>

<input type="text" autofocus name="searchValue" value="${param.searchValue}"/>

<input type="submit" value="검색"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

<!-- 선택되면 form태그 제출 -->

<select name="perPageNum" onchange="searchName.submit();">

<c:forEach var="i" begin="10" end="25" step="5">

<option value="${i}"${param.perPageNum eq i?'selected':''}>${i}개씩 보기</option>

</c:forEach>

</select>

</form>

</td>

</tr>

활용해서 검색한 내용 추가해줌.

 

 

 

pageMaker 클래스에 메소드 추가

public String makeQuery(int page) {

StringBuilder sb = new StringBuilder();

sb.append("?");

sb.append("page="+page);

sb.append("&perPageNum="+cri.getPerPageNum());

return sb.toString();

}

문자열 이어서 연산할때는 StringBuilder 사용

 

추가된 메소드 이용해서 페이징 블럭 구현

a태그에 요청경로 유의.

<!-- 페이징 블럭 출력 -->

<tr>

<th colspan="4">

<c:if test="${pm.first}">

<a href="notice_list.jsp${pm.makeQuery(1)}">[처음]</a>

</c:if>

<c:if test="${pm.prev}">

<a href="notice_list.jsp${pm.makeQuery(pm.startPage-1)}">[이전]</a>

</c:if>

<c:forEach var = "i" begin="${pm.startPage}" end="${pm.endPage}" step="1">

<a href="notice_list.jsp${pm.makeQuery(i)}">[${i}]</a>

</c:forEach>

<c:if test="${pm.next}">

<a href="notice_list.jsp${pm.makeQuery(pm.endPage+1)}">[다음]</a>

</c:if>

<c:if test="${pm.last}">

<a href="notice_list.jsp${pm.makeQuery(pm.maxPage)}">[마지막]</a>

</c:if>

</th>

</tr>

 

페이징 블럭에 검색 기능 반영하기

SearchCriteria, SearchPageMaker 클래스 파일 생성 (각자 Criteria, PageMaker 상속함) 및 notice_list.jsp 파일 수정 

 

<!-- 페이징 처리 -->

<jsp:useBean id="pm" class="util.SearchPageMaker" />

<jsp:useBean id="cri" class="util.SearchCriteria"/>

<jsp:setProperty property="*" name="cri"/>

 

<jsp:setProperty property="cri" name="pm" value="${cri}"/>

수정 후 필요없어져서 주석처리.

<%-- <!-- parameter로 전달된 사용자 요청 페이지 name:page -->

<c:if test="${!empty param.page}">

<c:set target="${pm.cri}" property="page" value="${param.page}"/>

</c:if>

<!-- 한 페이지에 보여줄 게시물 수 name:perPageNum -->

<c:if test="${!empty param.perPageNum}">

<c:set target="${pm.cri}" property="perPageNum" value="${param.perPageNum}"/>

</c:if>

--%>

<!-- 전체 게시물 개수 -->

<s:query var="r" dataSource="java/MySqlDB">

SELECT count(*) AS cnt FROM notice_board

<c:if test="${!empty pm.cri.searchValue}">

<c:choose>

<c:when test="${pm.cri.searchType eq 'title'}">

WHERE notice_title LIKE CONCAT('%','${pm.cri.searchValue}','%')

</c:when>

<c:otherwise>

WHERE notice_content LIKE CONCAT('%','${pm.cri.searchValue}','%')

</c:otherwise>

</c:choose>

</c:if>

</s:query>

<c:set target="${pm}" property="totalCount" value="${r.rows[0].cnt}"/>

<!-- 요청한 페이지 정보와 한페이지에 보여줄 게시물 개수를 연산하여 게시물 목록 검색 -->

<s:query var="rs" dataSource="java/MySqlDB" startRow="${pm.cri.startRow}"

maxRows="${pm.cri.perPageNum}">

SELECT * FROM notice_board

<c:if test="${!empty param.searchValue}">

<c:choose>

<c:when test="${param.searchType eq 'title'}">

WHERE notice_title LIKE '%${param.searchValue}%'

</c:when>

<c:otherwise>

WHERE notice_content LIKE '%${param.searchValue}%'

</c:otherwise>

</c:choose>

</c:if>

ORDER BY notice_num DESC

</s:query>

<c:if test="${rs.rowCount > 0}">

<jsp:useBean id="noticeList"

class="java.util.ArrayList"

type="java.util.List<vo.NoticeVO>" />

<c:forEach var="notice" items="${rs.rows}">

<jsp:useBean id="vo" class="vo.NoticeVO" />

<!-- 값채우기 -->

<c:forEach var="c" items="${rs.columnNames}">

<!-- 필드이름과 테이블의 속성 이름이 같아야 이렇게 사용이 가능하다.(다른 속성을 지정해놓고 AS로 별칭정의) -->

<c:set target="${vo}" property="${c}" value="${notice[c]}"/>

</c:forEach>

<c:set var="temp" value="${noticeList.add(vo)}"/>

<c:remove var="vo"/><!-- useBean으로 새로운 객체 생성하도록 삭제해줌 -->

</c:forEach>

</c:if>


질문답변 게시판 생성

 

회원들이 글 쓸 수 있도록 자유게시판 형태로 작성. sql내용이 많으니 member.sql 문서 참고하기.

 

LAST_INSERT_ID() : INSERT 후 PRIMARY KEY값을 가져온다.

는 동일한 트랜잭션에서만 사용이 가능하다.

 

-- 오토커밋 해제 후 작업함

INSERT INTO qna_board

VALUES(null,'최기근','테스트용 게시글입니다.','냉무',0,0,0,1,0,now());

SELECT * FROM qna_board ORDER BY qna_num DESC;

SELECT LAST_INSERT_ID();

 

UPDATE qna_board SET qna_re_ref = LAST_INSERT_ID()

WHERE qna_num = LAST_INSERT_ID();

 

commit;

모든 qna_re_ref가 수정될 수 있으므로 WHERE 조건 추가.

 

write처리 페이지에서 s:transaction으로 작업함(오류발생시 자동 rollback)

<jsp:useBean id="qnaBoard" class="vo.QnABoardVO" />

<jsp:setProperty property="*" name="qnaBoard"/>

<s:transaction dataSource="java/MySqlDB">

<s:update>

INSERT INTO qna_board (qna_name,qna_title,qna_content,qna_writer_num)

VALUES(?,?,?,?)

<s:param>${qnaBoard.qna_name}</s:param>

<s:param>${qnaBoard.qna_title}</s:param>

<s:param>${qnaBoard.qna_content}</s:param>

<s:param>${qnaBoard.qna_writer_num}</s:param>

</s:update>

<s:update var="result">

UPDATE qna_board SET qna_re_ref = LAST_INSERT_ID()

WHERE qna_num = LAST_INSERT_ID();

</s:update>

</s:transaction>

<c:choose>

<c:when test="${result > 0}">

<c:redirect url="qna_list.jsp"/>

</c:when>

<c:otherwise>

<script>

alert('게시글 등록 실패!');

history.go(-1);

</script>

</c:otherwise>

</c:choose>

 

답변글은 안쪽으로 들어가도록 구현해보자

 

<!-- qna_list.jsp -->

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="f" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="s" %>

<jsp:include page="../../common/header.jsp" />

<jsp:useBean id="cri" class="util.Criteria" />

<jsp:setProperty name="cri" property="*" />

<jsp:useBean id="pm" class="util.PageMaker"/>

<c:set target="${pm}" property="cri" value="${cri}"/>

 

<!-- 전체 게시물 개수 -->

<s:query var="r" dataSource="java/MySqlDB">

SELECT count(*) AS cnt FROM qna_board

</s:query>

<c:set target="${pm}" property="totalCount" value="${r.rows[0].cnt}"/>

 

<s:query var="rs" dataSource="java/MySqlDB">

SELECT * FROM qna_board

ORDER BY qna_re_ref DESC, qna_re_seq ASC

limit ${cri.startRow},${cri.perPageNum}

</s:query>

글 정보를 ref 내림차순, seq 오름차순으로 정렬하고 있다.

<c:choose>

<c:when test="${rs.rowCount > 0}">

<tr>

<th>글번호</th>

<th>제목</th>

<th>ref</th>

<th>lev</th>

<th>seq</th>

<th>작성자</th>

<th>작성시간</th>

<th>조회수</th>

</tr>

<c:forEach var="board" items="${rs.rows}">

<tr>

<td>${board.qna_num}</td>

<td style="text-align:left;padding:5px;">

<c:if test="${board.qna_re_lev != 0}">

<c:forEach begin="1" end="${board.qna_re_lev}">

&nbsp;&nbsp;&nbsp;

</c:forEach>

┗> <!-- ㅂ + 한자키 특수문자 추가 -->

</c:if>

<a href="qna_detail.jsp?qna_num=${board.qna_num}">

${board.qna_title}

</a>

</td>

<td>${board.qna_re_ref}</td>

<td>${board.qna_re_lev}</td>

<td>${board.qna_re_seq}</td>

<td>${board.qna_name}</td>

<td>${board.qna_date}</td>

<td>${board.qna_readcount}</td>

</tr>

</c:forEach>

 

상세보기(detail), update 페이지에서 qna_num을 사용하고 있어서 따로 jsp페이지 생성하고 include해줌.

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="f" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="s" %>

<!-- qna_select.jsp -->

<s:query var="rs" dataSource="java/MySqlDB">

SELECT * FROM qna_board WHERE qna_num = ?

<s:param>${param.qna_num}</s:param>

</s:query>

<c:set var="qna" value="${rs.rows[0]}" scope="request"/>

 

상세보기 클릭 시 조회수 증가 구현

<!-- 조회 수 증가 -->

<s:update dataSource="java/MySqlDB">

UPDATE qna_board SET qna_readcount = qna_readcount + 1

WHERE qna_num = ?

<s:param>${param.qna_num}</s:param>

</s:update>

 

qna_reply.jsp : 답변 작성 폼 페이지.

<!-- 원본글 번호 -->

<jsp:include page="qna_select.jsp"/>

 

<section class="wrap">

<h1> 답변 글 작성</h1>

<form action="qna_reply_submit.jsp" method="POST">

<input type="hidden" name="qna_writer_num" value="${member.u_num}"/>

<input type="hidden" name="qna_re_ref" value="${qna.qna_re_ref}"/>

<input type="hidden" name="qna_re_lev" value="${qna.qna_re_lev}"/>

<input type="hidden" name="qna_re_seq" value="${qna.qna_re_seq}"/>

<table>

<tr>

<td>작성자</td>

<td>

<input type="text" name="qna_name" required />

</td>

</tr>

qna_select를 include해서 qna 원본 글 정보를 받아준다.

아래는 ref,lev,seq 참고 자료.(sql문서)

-- 원본글(질문글)일 경우 자신의 게시글 번호를 저장하여

-- 동일한 qna_re_ref값일 경우 묶어서 출력할 수 있도록 저장

ALTER TABLE qna_board ADD COLUMN

qna_re_ref INT NOT NULL DEFAULT 0 AFTER qna_content;

 

-- view 화면에서 출력될 답변 글의 깊이 추가

ALTER TABLE qna_board ADD COLUMN

qna_re_lev INT NOT NULL DEFAULT 0 AFTER qna_re_ref;

 

--답변글 끼리의 정렬 순서 추가

ALTER TABLE qna_board ADD COLUMN

qna_re_seq INT NOT NULL DEFAULT 0 AFTER qna_re_lev;

 

qna_reply_submit : form태그 action화면.

1.기존에 원본글에 답변이 있는 경우,

기존 답변글의 seq에 1을 추가해서

지금 추가하는 답변글이 더 위쪽에 오도록 정렬함. (UPDATE SET 구문)

2. 원본 글보다 지금 추가 하는 글은 lev,seq가 1씩 추가된다.(원본글 밑에 답변글이 정렬되게함)

 ref는 원본글과 동일하게 해서 그룹화해준다.

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!-- qna_reply_submit.jsp -->

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="f" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="s" %>

<f:requestEncoding value="utf-8"/>

<jsp:useBean id="qnaBoard" class="vo.QnABoardVO"/>

<jsp:setProperty property="*" name="qnaBoard"/>

${qnaBoard}<br/>

<s:transaction dataSource="java/MySqlDB">

<s:update>

UPDATE qna_board SET qna_re_seq = qna_re_seq + 1

WHERE qna_re_ref = ? AND qna_re_seq > ?

<s:param>${qnaBoard.qna_re_ref}</s:param>

<s:param>${qnaBoard.qna_re_seq}</s:param>

</s:update>

<s:update>

INSERT INTO qna_board

VALUES(null,?,?,?,?,?,?,?,0,now());

<s:param>${qnaBoard.qna_name}</s:param>

<s:param>${qnaBoard.qna_title}</s:param>

<s:param>${qnaBoard.qna_content}</s:param>

<s:param>${qnaBoard.qna_re_ref}</s:param>

<s:param>${qnaBoard.qna_re_lev + 1}</s:param>

<s:param>${qnaBoard.qna_re_seq + 1}</s:param>

<s:param>${qnaBoard.qna_writer_num}</s:param>

</s:update>

</s:transaction>

<c:redirect url="qna_list.jsp"/>