모델2로 답변형 게시판 구현하기
1. sec03.brd01 패키지를 새로 만들고 관련된 클래스 추가합니다. 또한 board01 폴더를 만들고 listArticles.jsp를 추가합니다.

2. BoardController 클래스를 다음과 같이 작성합니다. 이 클래스는 /board/listArticles.do로 요청 시 화면에 글 목록을 출력하는 역할을 합니다. getPathInfo() 메서드를 이용해 action 값을 가져오고 null이거나 /listArticles.do일 경우 BoardService 클래스의 listArticles() 메서드를 호출해 전체 글을 조회합니다. 그리고 조회한 글을 articlesList 속성으로 바인딩하고 목록창(listArticles.jsp)으로 포워딩합니다.
package sec03.brd01;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class BoardController
*/
//@WebServlet("/board/*")
public class BoardController extends HttpServlet {
private static final long serialVersionUID = 1L;
BoardService boardService;
ArticleVO articleVO;
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
boardService = new BoardService();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String nextPage = "";
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
String action = request.getPathInfo();
System.out.println("action:" + action);
try {
List<ArticleVO> articlesList = new ArrayList<ArticleVO>();
if (action == null) {
articlesList = boardService.listArticles();
request.setAttribute("articlesList", articlesList);
nextPage = "/board01/listArticles.jsp";
} else if (action.equals("/listArticles.do")) {
articlesList = boardService.listArticles();
request.setAttribute("articlesList", articlesList);
nextPage = "/board01/listArticles.jsp";
}else {
nextPage = "/board01/listArticles.jsp";
}
RequestDispatcher dispatch = request.getRequestDispatcher(nextPage);
dispatch.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. BoardService 클래스를 다음과 같이 작성합니다. BoardDAO 객체를 생성한 후 selectAllArticle() 메서드를 호출해 전체 글을 가져옵니다.
package sec03.brd01;
import java.util.List;
public class BoardService {
BoardDAO boardDAO;
public BoardService() {
boardDAO = new BoardDAO();
}
public List<ArticleVO> listArticles() {
List<ArticleVO> articlesList = boardDAO.selectAllArticles();
return articlesList;
}
}
4. BoardDAO 클래스를 다음과 같이 작성합니다. BoardService 클래스에서 BoardDAO의 selectAllArticles() 메서드를 호출하면 계층형 SQL문을 이용해 계층형 구조로 전체 글을 조회한 후 반환합니다.
package sec03.brd01;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDAO {
private DataSource dataFactory;
Connection conn;
PreparedStatement pstmt;
public BoardDAO() {
try {
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");
dataFactory = (DataSource) envContext.lookup("jdbc/oracle");
} catch (Exception e) {
e.printStackTrace();
}
}
public List selectAllArticles() {
List articlesList = new ArrayList();
try {
conn = dataFactory.getConnection();
String query = "SELECT LEVEL,articleNO,parentNO,title,content,id,writeDate"
+ " from t_board"
+ " START WITH parentNO=0" + " CONNECT BY PRIOR articleNO=parentNO"
+ " ORDER SIBLINGS BY articleNO DESC";
System.out.println(query);
pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int level = rs.getInt("level");
int articleNO = rs.getInt("articleNO");
int parentNO = rs.getInt("parentNO");
String title = rs.getString("title");
String content = rs.getString("content");
String id = rs.getString("id");
Date writeDate = rs.getDate("writeDate");
ArticleVO article = new ArticleVO();
article.setLevel(level);
article.setArticleNO(articleNO);
article.setParentNO(parentNO);
article.setTitle(title);
article.setContent(content);
article.setId(id);
article.setWriteDate(writeDate);
articlesList.add(article);
}
rs.close();
pstmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return articlesList;
}
}
5. ArticleVO 클래스를 다음과 같이 작성합니다. 조회한 들을 저장하는 ArticleVO 클래스에 글의 깊이를 저장하는 level 속성을 추가합니다.
package sec03.brd01;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.Date;
public class ArticleVO {
private int level;
private int articleNO;
private int parentNO;
private String title;
private String content;
private String imageFileName;
private String id;
private Date writeDate;
public ArticleVO() {
}
public ArticleVO(int level, int articleNO, int parentNO, String title, String content, String imageFileName,
String id) {
super();
this.level = level;
this.articleNO = articleNO;
this.parentNO = parentNO;
this.title = title;
this.content = content;
this.imageFileName = imageFileName;
this.id = id;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getArticleNO() {
return articleNO;
}
public void setArticleNO(int articleNO) {
this.articleNO = articleNO;
}
public int getParentNO() {
return parentNO;
}
public void setParentNO(int parentNO) {
this.parentNO = parentNO;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getImageFileName() {
try {
if (imageFileName != null && imageFileName.length() != 0) {
imageFileName = URLDecoder.decode(imageFileName, "UTF-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return imageFileName;
}
public void setImageFileName(String imageFileName) {
try {
if (imageFileName != null && imageFileName.length() != 0) {
this.imageFileName = URLEncoder.encode(imageFileName, "UTF-8");//�����̸��� Ư�����ڰ� ���� ��� ���ڵ��մϴ�.
}else {
this.imageFileName = imageFileName;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Date getWriteDate() {
return writeDate;
}
public void setWriteDate(Date writeDate) {
this.writeDate = writeDate;
}
}
6. 이제 JSP에 글 목록을 표시해 보겠습니다. listArticles.jsp를 다음과 같이 작성합니다. 첫 번째 <forEach> 태그를 이용해 articlesList 속성으로 포워딩한 글의 목록을 차례로 전달받아 표시합니다. <forEach> 태그 반복 시 각 글의 level 값이 크면 답글이므로 다시 내부 <forEach> 태그를 이용해 1부터 level 값까지 반복하면서 공백을 만들고(들여쓰기) 답글을 표시합니다. 이때 level 값이 1보다 크지 않으면 부모 글이므로 공백 없이 표시합니다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
isELIgnored="false" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<%
request.setCharacterEncoding("UTF-8");
%>
<!DOCTYPE html>
<html>
<head>
<style>
.cls1 {text-decoration:none;}
.cls2{text-align:center; font-size:30px;}
</style>
<meta charset="UTF-8">
<title>글목록창</title>
</head>
<body>
<table align="center" border="1" width="80%" >
<tr height="10" align="center" bgcolor="lightgreen">
<td >글번호</td>
<td >작성자</td>
<td >제목</td>
<td >작성일</td>
</tr>
<c:choose>
<c:when test="${empty articlesList }" >
<tr height="10">
<td colspan="4">
<p align="center">
<b><span style="font-size:9pt;">등록된 글이 없습니다.</span></b>
</p>
</td>
</tr>
</c:when>
<c:when test="${!empty articlesList}" >
<c:forEach var="article" items="${articlesList }" varStatus="articleNum" >
<tr align="center">
<td width="5%">${articleNum.count}</td>
<td width="10%">${article.id }</td>
<td align='left' width="35%">
<span style="padding-right:30px"></span>
<c:choose>
<c:when test='${article.level > 1 }'>
<c:forEach begin="1" end="${article.level }" step="1">
<span style="padding-left:20px"></span>
</c:forEach>
<span style="font-size:12px;">[답변]</span>
<a class='cls1' href="${contextPath}/board/viewArticle.do?articleNO=${article.articleNO}">${article.title}</a>
</c:when>
<c:otherwise>
<a class='cls1' href="${contextPath}/board/viewArticle.do?articleNO=${article.articleNO}">${article.title }</a>
</c:otherwise>
</c:choose>
</td>
<td width="10%"><fmt:formatDate value="${article.writeDate}" /></td>
</tr>
</c:forEach>
</c:when>
</c:choose>
</table>
<a class="cls1" href="#"><p class="cls2">글쓰기</p></a>
</body>
</html>
7. http://localhost:8080/pro17/board/listArticles.do로 요청하여 글 목록이 우리가 원하는 대로 출력되는지 확인합니다. 자식 글은 앞에 level 값만큼 들여쓰기가 되고, [답변]이라는 텍스트 다음에 표시됩니다.
'프로그래밍 언어 > 자바 웹' 카테고리의 다른 글
| 글 상세 기능 구현 (0) | 2026.06.20 |
|---|---|
| 게시판 글쓰기 구현 (0) | 2026.06.17 |
| 회원 정보 수정 및 삭제 기능 구현 (0) | 2026.06.11 |
| 회원 정보 추가 기능 구현 (0) | 2026.06.08 |
| 회원 정보 조회 기능 구현 (0) | 2026.06.05 |