이전 포스팅의 내용에 추가적으로 작업되었으므로 필요하다면 전 게시글을 확인할 필요가 있다. 목차는 다음과 같다.
1. 스코프 이해 활용
1) model
2) view
3) controller
2. 페이징처리(더보기)
1) view
2) controller
작업 순서에 따라 코드는 간략하게 첨부할 예정이나, 아래의 깃허브 링크를 통해 모든 코드의 확인이 가능하다.
https://github.com/Hamjeonghui/m_2.git
1. 스코프 이해 활용
전 포스팅의 결과물로는 insertAction과 deleteAction등 DB에 전달과 분기처리는 가능하였지만, 단점이 분명히 존재했다. Action.class파일들의 성공 결과에 따라 그저 메인페이지로 이동하여 게시글의 전체 목록을 조회하게 할 뿐, 사용자의 편의성은 전혀 고려하지 않았는데, forward.setRedirect의 적절한 처리 방법에 대해 이해했으니 이제 그것을 활용하여볼 필요가 있다.
* 좋아요를 눌렀을때, 댓글 작성 및 삭제 했을때 해당하는 게시글의 상세보기가 되도록 ! *
1) model
DAO에 상세보기 로직의 추가가 필요하게 되므로 바로 작업한다. 아래의 메서드를 통해 하나의 게시글과 여러개의 댓글정보를 main에서 출력되게 할 예정이다. 이때 bid를 통해 상세보기가 가능하다. 추가한 메서드의 코드만을 첨부하였다.
package model.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import model.common.JDBCUtil;
import model.vo.BoardSet;
import model.vo.BoardVO;
import model.vo.ReplyVO;
public class BoardDAO { // BoardSet을 다루는 DAO클래스
Connection conn;
PreparedStatement pstmt;
//전체목록
static final String selectAll_board="select * from board order by bid desc limit 0,?"; // 페이징처리 pagination
//내가 쓴 글 전부 말고! 해당하는 글 하나!
static final String selecOne_board="select * from board where bid=?";
// 오라클에서는 rownum으로 대체하여 sql작성★
static final String selectAll_reply="select * from reply where bid=? order by rid desc";
// 글 1개랑 +댓글 출력 ☆
public ArrayList<BoardSet> selectOne(BoardVO vo){
ArrayList<BoardSet> datas=new ArrayList<BoardSet>();
conn=JDBCUtil.connect();
try {
System.out.println("dao로그 : 글 상세보기");
pstmt=conn.prepareStatement(selecOne_board);
pstmt.setInt(1, vo.getBid());
ResultSet rs=pstmt.executeQuery();
//검색 결과가 있으면
if(rs.next()) {
BoardSet bs=new BoardSet();
BoardVO boardVO=new BoardVO();
boardVO.setBdate(rs.getString("bdate"));
boardVO.setBid(rs.getInt("bid"));
boardVO.setContent(rs.getString("content"));
boardVO.setFavcnt(rs.getInt("favcnt"));
boardVO.setMid(rs.getString("mid"));
boardVO.setRpcnt(rs.getInt("rpcnt"));
bs.setBoardVO(boardVO);
ArrayList<ReplyVO> replyList=new ArrayList<ReplyVO>();
pstmt=conn.prepareStatement(selectAll_reply);
pstmt.setInt(1, rs.getInt("bid"));
ResultSet rs2=pstmt.executeQuery();
while(rs2.next()) {
ReplyVO replyVO=new ReplyVO();
replyVO.setBid(rs2.getInt("bid"));
replyVO.setMid(rs2.getString("mid"));
replyVO.setMsg(rs2.getString("msg"));
replyVO.setRdate(rs2.getString("rdate"));
replyVO.setRid(rs2.getInt("rid"));
replyList.add(replyVO);
}
rs2.close();
bs.setReplyList(replyList);
datas.add(bs);
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
JDBCUtil.disconnect(pstmt, conn);
return datas;
}
}
2) view
메서드가 사용될 수 있도록 좋아요, 댓글작성, 댓글삭제를 진행 했을때, controller에게 bid가 전달될 수 있게 코드를 수정한다.
① rmenu.tag
댓글을 삭제하게 될때, 해당 리뷰의 pk와 함께 리뷰에 참조되어있는 게시글번호(pk) 또한 함께 참조한다.
<%@ tag language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ attribute name="rid" %>
<%@ attribute name="mid" %>
<%@ attribute name="bid" %>
<c:if test="${member==mid}">
[<a href="deleteReply.do?rid=${rid}&bid=${bid}">삭제</a>]
</c:if>
② bmenu.tag
좋아요 기능을 수행하는데, bid에 해당하는 게시글을 참조할 수 있도록 한다.
<%@ tag language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ attribute name="bid" %>
<%@ attribute name="mid" %>
[ <a href="fav.do?bid=${bid}">♥</a> ]
<c:if test="${member==mid}">
|[<a href="deleteBoard.do?bid=${bid}">삭제</a>]
</c:if>
③ main.jsp
게시글의 상세정보 조회의 경우 ${data}를 통해 확인 가능하며, 상세조회가 아닐 경우는 ${datas}를 통해 여러개의 게시글을 확인할 수 있을 것이다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="kim" tagdir="/WEB-INF/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="css/style.css" type="text/css" />
</head>
<body>
<script type="text/javascript">
function newMember() {
window.open("signup.jsp", "newMember", "width=500,height=300");
}
</script>
<header>
<h1>댓글과 대댓글 실습예제</h1>
<nav>
<ul>
<li><a href="main.do">로고</a></li>
<li><kim:login /></li>
</ul>
</nav>
</header>
<div id="wrapper">
<section id="main">
<br>
<hr>
<form action="insertBoard.do" method="post">
<kim:board type="board" />
<input type="hidden" name="mid" value="${member}"> <input
type="submit" value="글 작성하기">
</form>
<hr>
<h2>게시글 목록</h2>
<!-- 게시글 상세보기를 하거나, 전체보기를 하거나! -->
<c:choose>
<c:when test="${data!=null}"> <!-- mainAction에서 data가 set되어있다면 상세보기 -->
<c:forEach var="bs" items="${data}">
<c:set var="vo" value="${bs.boardVO}" />
<div class="board">
<h3>
[${vo.bid}] ${vo.mid} >> ${vo.content} [댓글수 ${vo.rpcnt} | 좋아요
${vo.favcnt}] [${vo.bdate}]
<kim:bmenu bid="${vo.bid}" mid="${vo.mid}" />
</h3>
</div>
<div class="reply">
<form action="insertReply.do" method="post">
<kim:board type="reply" />
<input type="hidden" name="mid" value="${member}"> <input
type="hidden" name="bid" value="${vo.bid}"> <input
type="submit" value="댓글 작성하기">
</form>
</div>
<div class="replylist">
<c:forEach var="r" items="${bs.replyList}">
<h4>${r.mid}
>> ${r.msg} [${r.rdate}]
<kim:rmenu mid="${r.mid}" rid="${r.rid}" bid="${r.bid}"/>
</h4>
</c:forEach>
</div>
</c:forEach>
</c:when>
<c:otherwise>
<c:forEach var="bs" items="${datas}"> <!-- mainAction에서 datas가 set되어있다면 여러개 보기 -->
<c:set var="vo" value="${bs.boardVO}" />
<div class="board">
<h3>
[${vo.bid}] ${vo.mid} >> ${vo.content} [댓글수 ${vo.rpcnt} | 좋아요
${vo.favcnt}] [${vo.bdate}]
<kim:bmenu bid="${vo.bid}" mid="${vo.mid}" />
</h3>
</div>
<div class="reply">
<form action="insertReply.do" method="post">
<kim:board type="reply" />
<input type="hidden" name="mid" value="${member}"> <input
type="hidden" name="bid" value="${vo.bid}"> <input
type="submit" value="댓글 작성하기">
</form>
</div>
<div class="replylist">
<c:forEach var="r" items="${bs.replyList}">
<h4>${r.mid}
>> ${r.msg} [${r.rdate}]
<kim:rmenu mid="${r.mid}" rid="${r.rid}" bid="${r.bid}" />
</h4>
</c:forEach>
</div>
</c:forEach>
</c:otherwise>
</c:choose>
</section>
</div>
<footer>
<p>ⓒCOPYRIGHT</p>
</footer>
</body>
</html>
3) controller
① DeleteReplyAction
이 페이지에서 알고있는 bid를 다음 이동페이지에서도 알고 있어야만 bid를 통해 게시글의 상세보기가 가능해진다. 이때 sendRedirect를 false로 설정하여 모든 request와 response를 그대로 전달하기 때문에 굳이 setAttribute해줄 필요는 없다.
package controller.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.vo.ReplyVO;
public class DeleteReplyAction implements Action{
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=null;
BoardDAO dao=new BoardDAO();
ReplyVO vo=new ReplyVO();
vo.setRid(Integer.parseInt(req.getParameter("rid")));
if(dao.deleteReply(vo)) {
forward=new ActionForward();
forward.setPath("main.do");
//메인으로 갈때 내가(request로) 알고있는 bid를 너도 알 필요가 있어!
forward.setRedirect(false);
}
return forward;
}
}
② InsertReplyAction
마찬가지의 논리이다.
package controller.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.vo.ReplyVO;
public class InsertReplyAction implements Action{
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=null;
BoardDAO dao=new BoardDAO();
ReplyVO vo=new ReplyVO();
vo.setBid(Integer.parseInt(req.getParameter("bid")));
vo.setMid(req.getParameter("mid"));
vo.setMsg(req.getParameter("msg"));
if(dao.insertReply(vo)) {
forward=new ActionForward();
forward.setPath("main.do");
//내가 알고있는 mid,bid를 main에서도 알게 할 필요가 있다!
forward.setRedirect(false);
}
return forward;
}
}
③ FavAction
package controller.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.vo.BoardVO;
public class FavAction implements Action{
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=null;
BoardDAO dao=new BoardDAO();
BoardVO vo=new BoardVO();
vo.setBid(Integer.parseInt(req.getParameter("bid")));
if(dao.update(vo)) {
forward=new ActionForward();
forward.setPath("main.do");
//내가 아는 bid를 main에서 알 필요가 있어!
forward.setRedirect(false);
}
return forward;
}
}
④ MainAction
아래의 로직을 통해 넘겨받은 bid가 존재한다면 상세보기를, 아니라면 전체보기 혹은 내가 쓴 글 보기를 수행하게 된다.
package controller.action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.vo.BoardSet;
import model.vo.BoardVO;
public class MainAction implements Action{
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=new ActionForward();
BoardDAO dao=new BoardDAO();
BoardVO vo=new BoardVO();
System.out.println(req.getParameter("bid"));
// # 댓글작성, 댓글삭제, 좋아요 기능 사용시 bid를 참조하여 그 글의 상세목록을 메인에 출력! #
//앞에서 bid 넘어온거 있어?
if(req.getParameter("bid")!=null) {
System.out.println("게시글 selectOne 보기");
vo.setBid(Integer.parseInt(req.getParameter("bid")));
ArrayList<BoardSet> data = dao.selectOne(vo);
req.setAttribute("data", data);
System.out.println(data);
} else {//bid넘어온거 없으면 전체목록 or 내가 쓴 글 메인에 출력!
System.out.println("게시글 selectAll 보기");
// 세션으로 부른애 말고! 파라미터로 불러오는애로 넣자!
// 세션으로 넣으면 한 번 로그인하면 null이 없는데? 계속 선택보기 될텐데???
vo.setMid(req.getParameter("mid"));
ArrayList<BoardSet> datas=dao.selectAll(vo, 3);
req.setAttribute("datas", datas);
System.out.println(datas);
}
//datas나 data가지고 메인으로 곧장 가
forward.setPath("main.jsp");
forward.setRedirect(false);
return forward;
}
}
2. 페이징처리(더보기)
1) view
더보기 기능을 위한 변수의 이름은 b(정수)로 선언하였다. b를 클릭할때마다 +2가 누적되도록 하며, 이때 mid를 함께 넘겨줌으로써 "내가 쓴 글 보기"와 함께 더보기 기능도 추가로 사용할 수 있게 된다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="kim" tagdir="/WEB-INF/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="css/style.css" type="text/css" />
</head>
<body>
<script type="text/javascript">
function newMember() {
window.open("signup.jsp", "newMember", "width=500,height=300");
}
</script>
<header>
<h1>댓글과 대댓글 실습예제</h1>
<nav>
<ul>
<li><a href="main.do">로고</a></li>
<li><kim:login /></li>
</ul>
</nav>
</header>
<div id="wrapper">
<section id="main">
<br>
<hr>
<form action="insertBoard.do" method="post">
<kim:board type="board" />
<input type="hidden" name="mid" value="${member}"> <input
type="submit" value="글 작성하기">
</form>
<hr>
<h2>게시글 목록</h2>
<!-- 더보기 : 더보기를 누르면 2개씩 늘어나도록!, 이때 mid같이 넘겨주면 내가 쓴 글 확인 가능 -->
<b><a href="main.do?b=${b+2}&mid=${mid}">더보기 >></a></b>
<!-- 게시글 상세보기를 하거나, 전체보기를 하거나! -->
<c:choose>
<c:when test="${data!=null}"> <!-- mainAction에서 data가 set되어있다면 상세보기 -->
<c:forEach var="bs" items="${data}">
<c:set var="vo" value="${bs.boardVO}" />
<div class="board">
<h3>
[${vo.bid}] ${vo.mid} >> ${vo.content} [댓글수 ${vo.rpcnt} | 좋아요
${vo.favcnt}] [${vo.bdate}]
<kim:bmenu bid="${vo.bid}" mid="${vo.mid}" />
</h3>
</div>
<div class="reply">
<form action="insertReply.do" method="post">
<kim:board type="reply" />
<input type="hidden" name="mid" value="${member}"> <input
type="hidden" name="bid" value="${vo.bid}"> <input
type="submit" value="댓글 작성하기">
</form>
</div>
<div class="replylist">
<c:forEach var="r" items="${bs.replyList}">
<h4>${r.mid}
>> ${r.msg} [${r.rdate}]
<kim:rmenu mid="${r.mid}" rid="${r.rid}" bid="${r.bid}"/>
</h4>
</c:forEach>
</div>
</c:forEach>
</c:when>
<c:otherwise>
<c:forEach var="bs" items="${datas}"> <!-- mainAction에서 datas가 set되어있다면 여러개 보기 -->
<c:set var="vo" value="${bs.boardVO}" />
<div class="board">
<h3>
[${vo.bid}] ${vo.mid} >> ${vo.content} [댓글수 ${vo.rpcnt} | 좋아요
${vo.favcnt}] [${vo.bdate}]
<kim:bmenu bid="${vo.bid}" mid="${vo.mid}" />
</h3>
</div>
<div class="reply">
<form action="insertReply.do" method="post">
<kim:board type="reply" />
<input type="hidden" name="mid" value="${member}"> <input
type="hidden" name="bid" value="${vo.bid}"> <input
type="submit" value="댓글 작성하기">
</form>
</div>
<div class="replylist">
<c:forEach var="r" items="${bs.replyList}">
<h4>${r.mid}
>> ${r.msg} [${r.rdate}]
<kim:rmenu mid="${r.mid}" rid="${r.rid}" bid="${r.bid}" />
</h4>
</c:forEach>
</div>
</c:forEach>
</c:otherwise>
</c:choose>
</section>
</div>
<footer>
<p>ⓒCOPYRIGHT</p>
</footer>
</body>
</html>
2) controller
view에서 b라는 변수를 필요로 하기에 이 곳에서 b를 선언해줄 필요가 있다. 이때 기존의 b에 담길 수는 초기 페이지의 글 개수인 3개 이다. 만일 메인페이지에서 "더보기" 기능을 위해 b+2를 전달한다면 그것이 페이지의 게시글 출력 개수가 된다.
package controller.action;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.dao.BoardDAO;
import model.vo.BoardSet;
import model.vo.BoardVO;
public class MainAction implements Action{
@Override
public ActionForward execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
ActionForward forward=new ActionForward();
BoardDAO dao=new BoardDAO();
BoardVO vo=new BoardVO();
System.out.println(req.getParameter("bid"));
System.out.println(req.getParameter("mid"));
// # 댓글작성, 댓글삭제, 좋아요 기능 사용시 bid를 참조하여 그 글의 상세목록을 메인에 출력! #
//앞에서 bid 넘어온거 있어?
if(req.getParameter("bid")!=null) {
System.out.println("게시글 selectOne 보기");
vo.setBid(Integer.parseInt(req.getParameter("bid")));
ArrayList<BoardSet> data = dao.selectOne(vo);
req.setAttribute("data", data);
System.out.println(data);
} else {//bid넘어온거 없으면 전체목록 or 내가 쓴 글 메인에 출력!
System.out.println("게시글 selectAll 보기");
//view에서 "더보기" 누르면 작동할 수 있도록!
int b= 3;//main에 표시될 게시글 개수! 일단 처음엔 3개 보여주고,
if(req.getParameter("b")!=null) {//"더보기(${b+2})를 누르면"
b= Integer.parseInt(req.getParameter("b")); //그럼 이제 걔가 b겠지
}
//view에서 ${b}쓰니까 여기서 b가 누군지 정의
req.setAttribute("b", b);
System.out.println("b"+b);//로그
// 세션으로 부른애 말고! 파라미터로 불러오는애로 넣자!
// 세션으로 넣으면 한 번 로그인하면 null이 없는데? 계속 선택보기 될텐데???
vo.setMid(req.getParameter("mid"));
ArrayList<BoardSet> datas=dao.selectAll(vo, b);
req.setAttribute("datas", datas);
req.setAttribute("mid", req.getParameter("mid"));
System.out.println(datas);
}
//datas나 data가지고 메인으로 곧장 가
forward.setPath("main.jsp");
forward.setRedirect(false);
return forward;
}
}
이때 "내가 쓴 글 보기"기능을 위해 mid를 전달받는다면, 해당 mid를 setAttribute하여 다음페이지에서도 "내가 쓴 글 보기"가 유지되도록 한다. 한번 클릭 되었을때 request가 잊혀지지 않아 계속해서 mid는 빙글빙글 돌며 전달되게 된다.
이때 b변수 또한 계속해서 클릭된다면 mid가 유지되는 채로 페이징처리가 진행될 것이다. (태그파일 첨부)
<%@ tag language="java" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:choose>
<c:when test="${member!=null}">
<form action="logout.do" method="post">
<a href="main.do?mid=${member}">${memberName}님 환영합니다!</a>
<input type="submit" value="로그아웃">
</form>
</c:when>
<c:otherwise>
<form action="login.do" method="post">
아이디: <input type="text" name="mid">
비밀번호:<input type="password" name="mpw">
<input type="submit" value="로그인">
<a href="signup.jsp">회원가입</a>
</form>
</c:otherwise>
</c:choose>
메인페이지에서 "로고"버튼을 통해 mid가 전달되지 않게 되면 비로소 전체 목록을 확인할 수 있게 된다.
'JSP' 카테고리의 다른 글
[JSTL] 현재 날짜 구하기 (0) | 2022.09.27 |
---|---|
[게시판 Ver.2] 내가 쓴 글 목록 보기 (0) | 2022.03.16 |
[게시판 Ver.2] 커스텀태그_응용 (0) | 2022.03.15 |
[게시판 Ver.2] 게시글과 댓글의 화면 출력 (0) | 2022.03.14 |
[JDBC] MVC나누기 3_게시판+FC,필터,리스너 (0) | 2022.03.11 |