<!-- 요청한 페이지 정보와 한페이지에 보여줄 게시물 개수를 연산하여 게시물 목록 검색 -->
<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="검색"/>
<!-- 선택되면 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}">
</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"/>
'Java > JSP' 카테고리의 다른 글
7.14 실습파일 모델 1에서 mvc패턴으로 바꿔보기 (0) | 2023.07.23 |
---|---|
7.20 qna 삭제 여부 추가(7.14실습 파일) (0) | 2023.07.20 |
07.17 JSTL 실습문제 풀이(07.14파일) (0) | 2023.07.17 |
7.14 JSTL() (0) | 2023.07.14 |
7.13 웹 MVC, EL, 스탠다드 태그 라이브러리 (0) | 2023.07.13 |