자바(JAVA)/JSP 웹 프로그래밍 공부 (성낙현의 JSP 자바 웹 프로그래밍 참고)

JAVA/JSP 23. 모델1 방식의 회원제 게시판 만들기 - 게시판 목록 페이지

개발학생 2023. 12. 30. 16:43
반응형

게시판 목록 페이지

  • 페이지 개념 없이, 전체 게시물을 한꺼번에 출력하는 형태
  • 목록 처리 프로세스와 담당 모듈(파일)

 

1. DTO와 DAO 준비 (오라클 연결을 위한 준비)

1) board 테이블에 데이터를 저장하거나 전송하기 위한 DTO 클래스 생성

  • 프로젝트에서 Java Resources 폴더 → src 폴더 → model1폴더 → board 폴더 → BoardDTO.java 파일 생성
// Java Resources/src/model1/board/BoardDTO.java

package model1.board;    //1.

public class BoardDTO {
		//2.멤버 변수 선언
		private String num;
		private String title;
		private String content;
		private String id;
		private java.sql.Date postdate;
		private String visitcount;
		private String name;    //3.

		//4.게터/세터
		public String getNum() {
				return num;
		}
		public void setNum(String num) {
				this.num = num;
		}
		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 void getId() {
				return id;
		}
		public void setId(String id) {
				this.id = id;
		}
		public java.sql.Date getPostdate() {
				return postdate;
		}
		public void setPostdate(java.sql.Date postdate) {
				this.postdate = postdate;
		}
		public String getVisitcount() {
				return visitcount;
		}
		public void setVisitcount(String visitcount) {
				this.visitcount = visitcount;
		}
		public String getName() {
				return name;
		}
		public void setName(String name) {
				this.name = name;
		}
}
  1. 패키지를 model1.board로 선언
  2. 멤버 변수를 board 테이블의 컬럼과 동일하게 작성, 자바빈즈 규약에 따라 접근 지정자는 private로 지정, 자료형은 특별한 이유는 없으므로 String으로 선언
  3. board 테이블에는 작성자의 아이디만 저장되므로, 목록 출력 시 이름 출력 불가→ DTO는 필요한 경우, 다른 테이블의 컬럼을 멤버 변수로 추가할 수 있음
    → 이름(name 컬럼) 출력 시 member 테이블과 조인(Join) 사용
  4. 멤버 변수를 선언하였다면, 게터와 세터 메서드는 [Source] → [Generate Getters and Setters..] 메뉴로 자동으로 생성할 수 있음

 

2) 데이터베이스에 접근하여 CRUD 작업을 수행하기 위해 DAO 클래스 생성

  • 프로젝트에서 Java Resources 폴더 → src 폴더 → model1폴더 → board 폴더 → BoardDAO.java 파일 생성
// Java Resources/src/model1/board/BoardDAO.java

package model1.board;    //1.

import javax.servlet.ServletContext;
import common.JDBConnect;

public class BoardDAO extends JDBConnect {    //2. 
		public BoardDAO(ServletContext application) {
				super(application);    //3.
		}
}
  1. BoardDTO 클래스와 같은 패키지
  2. 이전에 생성했던 JDBConnect 클래스를 상속함
  3. 생성자에서 부모 클래스의 생성자 호출→ 이 생성자는 매개 변수로 받은 application 내장 객체를 통해 web.xml에 정의해둔 오라클 접속 정보를 직접 가져와서 DB에 연결해줌
    → 부모 클래스인 JDBConnect에는 총 3개의 생성자를 정의했는데, 그 중 application 내장 객체를 받는 생성자를 이용함

 

2. JSP 페이지 구현

1) 게시물 개수 세기

  • BoardDAO.java에 selectCount() 메소드 추가 → select count(*) from board; 를 실행한 결과를 반환
// Java Resources/src/model1/board/BoardDAO.java

...생략...
import java.util.Map;    //1.

public class BoardDAO extends JDBConnect {
		...생성자 생략...
		
		//검색 조건에 맞는 게시물의 개수 반환
		public int selectCount(Map<String, Object>map) {    //2.
				int totalCount = 0;    //결과(게시물 수)를 담을 변수
				
				//3.게시물 수를 얻어오는 쿼리문 작성
				String query = "select count(*) from board";
				if (map.get("searchWord") != null) {    //4.
						query += " where " + map.get("searchField") + " "
										+ " like '%" + map.get("searchWord") + "%'";
				}
				
				try {    //5.
						stmt = con.createStatement();    //6.쿼리문 생성
						rs = stmt.executeQuery(query);    //7.쿼리 실행
						rs.next();    //8.커서를 첫 번째 행으로 이동
						totalCount = rs.getInt(1);    //9.첫 번째 컬럼 값을 가져옴
				}
				catch (Exception e) {
						System.out.println("게시물 수를 구하는 중 예외 발생");
						e.printStackTrace();
				}
				
				return totalCount;    //10.
		}
}
  1. selectCount() 코드에서 사용하는 외부 클래스를 임포트함 (Ctrl + Shift + O로 자동으로 추가할 수 있음)
  2. 게시물 개수를 알려주는 메소드 정의 - 매개변수로 받은 Map<String, Object> 컬렉션에는 게시물 검색을 위한 조건(=검색어)이 담겨 있음
  3. 게시물의 개수를 얻어오는 쿼리문 작성 - SQL이 제공하는 count(*) 한수 사용
  4. if문을 써서 검색어가 있는 경우(Map 컬렉션에 “searchWord” 키로 저장된 값이 있을 때) where 절 추가
  5. try/catch문으로 감쌈 - JDBC 프로그래밍은 기본적으로 예외처리를 해야 하기 때문
  6. 정적 쿼리문 실행을 위해, Statement 객체를 생성
  7. 6.에서 생성한 객체의 쿼리문 실행 - 결과는 ResultSet 객체로 반환 (ResultSet 객체는 행 단위로 저장되며, 현재 행을 가리키는 커서를 통해 값을 읽어오는 구조)
  8. next()로 커서를 최초 행으로 이동시킴
  9. 게시물 개수 추출 - count(*) 함수가 반환하는 값은 정수이므로 getInt() 사용 (숫자 1은 select절에 명시된 컬럼의 인덱스를 의미)
  10. 추출한 값을 반환 (JSP로 반환)

 

*만약 사용자가 검색 항목으로 ‘제목’을 선택한 후 “홍길동”이라고 입력하고 [검색하기] 버튼을 누른다면, 쿼리문에는 where절이 추가되어야 함

→ select count(*) from board where title like ‘%홍길동%’; //like를 사용해, title 컬럼에서 검색어로 입력한 단어가 포함된 레코드를 찾게 됨

⇒ 이 쿼리문을 실행한 후 결과를 얻는 코드

stmt = con.createStatement();    //쿼리문을 실행하기 위해 Statement 객체 생성
rs = stmt.executeQuery(query);   //select 쿼리문을 실행, 실행 결과는 ResultSet 객체로 반환
rs.next();                       //커서를 이동시켜 결괏값이 있는지 확인
totalCount = rs.getInt(1);       //ResultSet 객체의 1번 인덱스의 결과를 정수로 추출

 

 

2) 게시물 목록 가져오기

  • BoardDAO.java에 selectList() 메소드 추가
// Java Resources/src/model1/board/BoardDAO.java

...생략...

public class BoardDAO extends JDBConnect {
		...생략...
		public int selectList(Map<String, Object>map) {...생략...}

		//검색 조건에 맞는 게시물 목록 반환
		public List<BoardDTO> selectList(Map<String, Object>map) {    //1.
				List<BoardDTO> bbs = new Vector<BoardDTO>();    //2.결과(게시물 목록)를 담을 변수
				
				String query = "select * from board";    //3.
				
				if (map.get("searchWord") != null) {    //4.
						query += " where " + map.get("searchField") + " "
										+ " like '%" + map.get("searchWord") + "%' ";
				}
				query += " order by num desc ";    //5.

				try {
						stmt = con.createStatement();    //6.쿼리문 생성
						rs = stmt.executeQuery(query);    //7.쿼리실행

						while (rs.next())    //8.결과를 순회하며 한 행(게시물 하나)의 내용을 DTO에 저장
								//9.(아래 코드 7줄)
								BoardDTO dto = new BoardDTO();

								dto.setNum(rs.getString("num"));            //일련번호
								dto.setTitle(rs.getString("title"));        //제목
								dto.setContent(rs.getString("content"));    //내용
								dto.setPostdate(rs.getDate("postdate"));    //작성일
								dto.setId(rs.getString("id"));              //작성자 아이디
								dto.setVisitcount(rs.getString("visitcount"));    //조회수

								bbs.add(dto);    //10.결과 목록에 저장
						}
				}
				catch (Exception e) {
						System.out.println("게시물 조회 중 예외 발생");
						e.printStackTrace();
				}

				return bbs;    //11.
		}
}
  1. 연결된 데이터베이스로부터 게시물 목록을 가져오는 메소드 정의 - ‘검색 조건’을 매개변수로 받음
  2. 테이블에서 레코드를 가져올 때는 항상 List 계열의 컬렉션에 저장함 (여기서는 Vector를 사용했지만, ArrayList/LinkedList 등 List 계열 컬렉션이면 모두 동일하게 사용 가능)
    → List 컬렉션에는 데이터가 순서대로 저장되어 인덱스를 통해 가져올 수 있기 때문
  3. 목록을 가져오기 위해 쿼리문 작성
  4. 검색어가 있다면 where절을 추가
  5. 게시물 정렬을 위한 order by절 - 게시판 목록은 항상 최근 게시물이 상단에 출력되므로, 일련번호 컬럼 num을 내림차순(desc)으로 정렬
  6. Statement 객체 생성
  7. 6.에서 생성한 객체로 쿼리문 실행 (결과는 ResultSet 객체에 저장되어 반환됨)
  8. next() 메소드 - ResultSet에 저장된 행이 있는지 확인 (있다면 true 반환+커서를 첫 번째 행으로 이동시킴)
    → while문과 함께 사용: 더 이상 행이 없을 때까지 중괄호 안의 작업 반복
  9. while문 안: 하나의 행(게시물 하나)의 내용을 DTO 객체에 저장
  10. 9.의 DTO를 List 컬렉션에 담음 - while 루프를 끝까지 돌고 나면, 쿼리문으로 받아온 게시물 목록이 모두 List 컬렉션인 bbs에 저장됨
  11. 쿼리 결과를 모두 담은 List 컬렉션을 JSP로 반환

 

3) 게시글 목록 출력하기

  • 게시글 목록을 화면에 출력해주는 JSP 파일 생성
  • 프로젝트의 WebContent 폴더 → Board 폴더에 List.jsp 파일 생성(코드 앞부분)
// WebContent/Board/List.jsp

<%@ page import="java.util.List"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="java.util.Map"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
		pageEncoding="UTF-8"%>
<%
//1.DAO를 생성해 DB에 연결
BoardDAO dao = new BoardDAO(application);

//2.사용자가 입력한 검색 조건을 Map에 저장
Map<String, Object> param = new HashMap<String, Object>();

String searchField = request.getParameter("searchField");
String searchWord = request.getParameter("searchWord");
if (searchWord != null) {
		param.put("searchField", searchField);
		param.put("searchWord", searchWord);
}

int totalCount = dao.selectCount(param);    //3.게시물 수 확인
List<BoardDTO> boardLists = dao.selectList(param);    //4.게시물 목록 받기
dao.close();    //DB 연결 닫기
%>

<!DOCTYPE html>
<html>
<head>
		<meta charset="UTF-8">
		<title>회원제 게시판</title>
</head>
<body>
		...생략(코드 뒷부분)...
</body>
</html>
  1. BoardDAO 객체 생성 (DAO 생성 과정에서 DB와의 연결이 완료됨)
  2. 사용자가 검색폼에서 입력한 내용을 Map 컬렉션에 저장
    → DAO의 메소드를 호출할 때, 이 컬렉션을 매개변수로 전달할 것

*DAO가 제공하는 메소드 호출!

3. 게시물의 개수 (2.에서 만든 검색 조건을 매개변수로 전달)

4. 게시물 목록 (2.에서 만든 검색 조건을 매개변수로 전달)

 

  • List.jsp 파일(코드 뒷부분)
// WebContent/Board/List.jsp

...생략...
<body>
		<jsp:include page=".../Common/Link.jsp" /> <!-- 공통 링크 -->
		<h2>목록 보기(List)</h2>
		<!-- 1. 검색폼 -->
		<form method="get">    <!-- 2 -->
		<table border="1" width="90%">
		<tr>
				<td align="center">
						<select name="searchField">    <!-- 3 -->
								<option value="title">제목</option>
								<option value="content">내용</option>
						</select>
						<input type="text" name="searchWord" />
						<input type="submit" value="검색하기" />
				</td>
		</tr>
		</table>
		</form>
		<!-- 4.게시물 목록 테이블(표) -->
		<table border="1" width="90%">
				<!-- 5.각 컬럼의 이름 -->
				<tr>
						<th width="10%">번호</th>
						<th width="50%">제목</th>
						<th width="15%">작성자</th>
						<th width="10%">조회수</th>
						<th width="15%">작성일</th>
				</tr>
				<!-- 6.목록의 내용 -->
<%
if (boardLists.isEmpty()) {
		//7.게시물이 하나도 없을 때
%>
				<tr>
						<td colspan="5" align="center">
								등록된 게시물이 없습니다.
						</td>
				</tr>
<%
}
else {
		//8.게시물이 있을 때
		int virtualNum = 0;    //화면상에서의 게시물 번호
		for (BoardDTO dto : boardLists)
		{
				virtualNum = totalCount--;    //전체 게시물 수에서 시작해 1씩 감소 
%>
				<tr align="center">
						<td><%= virtualNum %></td>    <!-- 게시물 번호 -->
						<td align="left">    <!--제목(+ 하이퍼링크)-->
								<a href="View.jsp?num=<%= dto.getNum() %>"><%= dto.getTitle %><a>    <!-- 9. -->
						</td>

						<td align="center"><%= dto.getId() %></td>
						<td align="center"><%= dto.getVisitcount() %></td>
						<td align="center"><%= dto.getPostdate() %></td>
				</tr>
<%
		}
}
%>
		</table>
		<!-- 10.목록 하단의 [글쓰기] 버튼 -->
		<table border="1" width="90%">
				<tr align="right">
						<td><button type="button" onclick="location.href='Write.jsp';">글쓰기</button></td>
				</tr>
		</table>
</body>
</html>
  1. 검색폼
  2. 전송 방식은 get 방식이고, action 속성을 지정하지 않았으므로 submit하면 폼값이 현재 페이지로 전송됨
  3. 검색 항목(searchField)은 제목과 내용 중 선택할 수 있음 → 검색어가 없을 때와 있을 때를 구분하여 처리
  4. 검색 목록이 표 형태로 출력됨
  5. 표의 첫 줄은 각 컬럼의 이름이 옴
  6. 목록의 내용
  7. List 컬렉션에 저장된 내용이 하나도 없다면 간략하게 “등록된 게시물이 없습니다.”를 출력
  8. List 컬렉션에 저장된 게시물이 있다면 for문을 돌면서 하나씩 출력 → 게시물 정보는 모두 DTO 객체로부터 얻음
  9. 제목에 상세 보기 페이지로 이동하기 위한 링크가 추가됨 → 상세 보기는 일련번호를 통해 게시물을 조회하므로, num을 매개변수로 전달하고 있음
  10. [글쓰기] 버튼이 화면의 맨 아래에 위치함

 

4) List.jsp 파일 실행 결과

(1) 게시글을 불러오지 못했을 때

 

(2) 게시글 하나를 불러왔을 때

 

(3) 게시글 목록을 모두 불러왔을 때

  • 더미 데이터 여러 개 추가 (cmd에서 sqlplus를 입력하고 ‘hello’, 1234로 로그인함)

 

  • 웹 브라우저 새로고침 (F5키 입력) - 추가한 게시물들이 모두 잘 출력됨

 

 

(4) 게시물 검색 기능 동작 확인

  • 검색폼에서 ‘제목’을 선택하고, ‘겨울’이라고 입력한 후 [검색하기] 클릭
    → List.jsp 파일의 코드에서 요청 객체의 getParameter()로 매개변수를 받아, Map 컬렉션에 저장한 후 DAO로 전달 (조건에 맞는 결과만 가져옴)
    → 검색 항목과 검색어가, 주소표시줄 뒷부분의 쿼리스트링을 통해 전송되게 됨

 

  • 검색폼에서 ‘내용’을 선택하고, ‘여’이라고 입력한 후 [검색하기] 클릭
    → 위와 같은 원리

 

 

 

 

반응형