온라인 강좌/JSP & Servlet 활용

21차시 Project - 게시판 등록, 조회

범박사 2023. 7. 5. 22:46

학습목표

게시판 등록, 조회를 구현할 수 있다.

JDBC PreparedStatement에 대해 설명할 수 있다.

 

게시판 등록. 조회

 

Statement

  • JDBC 작성은 데이터베이스에서 원하는 SQL 문을 실행시켜 결과 값을 얻기 위함
  • 실제 데이터베이스에서 SQL문이 함수를 call 하는 시점에 매개 변수로 SQL 문을 지정함
  • SQL을 실행시키는 API
  • 객체 생성 시점에 SQL 문을 지정하지 않음
conn.createStatement();

SQL 문을 실행 메소드의 인자로 줌

  • st.execute(sql) : 수행결과가 ResultSet이면 true, 아니면 false 리턴
  • st.executeQuery(sql) : Select문 수행결과를 ResultSet에 담아서 리턴함
  • st.executeUpdate(sql) : Row 수를 리턴, Insert / Update / Delete문 수행 시 사용
rs = st.executeQuery(sql);

 

PreparedStatement

  • Statement interface를 상속한 interfacce
  • SQL 문은 동일하고 변수의 값만 다른 경우에 사용하면 효율적임 (데이터만 바꿔야할 때)
  • SQL 문을 어디서 지정하느냐 차이가 있음
    • Connection의 prepareStatement() 함수로 객체 획득
    • 객체 획득 시점에 SQL문 지정
conn.prepareStatement(sql);
  • SQL 문에 데이터 부분을 ?로 처리
  • ?는 이후 지정되는 데이터를 의미함
  • SQL 문의 포맷을 미리 준비해놓고 실행 시 데이터 변경만 하여 계속 동일한 구조의 SQL 문 실행
update board set title=?, content=? where seq=?
  • SQL문 실행 전에 setXxx()로 ?에 데이터 바인딩
ps.setInt(1, 1036);
ps.setString(2, "test");

실행 직전엔 무조건 ?에 해당하는 데이터를 지정해야 함

 

SQL 문을 실행 메소드의 인자로 주지 않음

  • ps.execute() : 수행결과가 ResultSet이면 true, 아니면 false 리턴
  • ps.executeQuery() : Select문 수행결과를 ResultSet에 담아서 리턴함
  • ps.executeUpdate() : Row 수를 리턴
Statement와 다른 점은?
실행시키는 함수의 매개변수가 SQL 문이 아님
--> 매개변수 필요 없기 때문

 

CallableStatement

  • PreparedStatement interface를 상속한 Interface
  • Connection 객체의 prepareCall()로 생성
cs = conn.prepareCall(function);

일반 SQL 문과 다른 점은 데이터베이스의 저장 프로시저 등을 실행시키기 위한 Statement라는 것

 

Stored prodecure/function을 실행하는데 사용됨

  • procedure : "{call procedure_name([variable1, variable 1, variable 1, ...])}"
  • function : "{?=call function_name([variable1, variable 1, variable 1, ...])}"

variable은 ?로 표현함

String function = "{?=call salary incF(?, ?)}";  // Function Call
String procedure = "{?=call salary inc(?, ?, ?)}";  // procedure Call

INPUT 변수에 값을 Biding하고, OUTPUT 변수의 Type을 설정함

  • Input binding : setXXX(index, variable_value) - index는 1부터 시작
  • Output 변수 Type 설정 : registerOutParameter(index, Types, XXX)

CallableStatement 실행은 execute() Method를 주로 이용

cs.setInt(2, 1119);
cs.setInt(3, 10);
cs.registerOutParameter(1, Types.INTEGER);
cs.execute();

결과 값은 CallableStatement 객체의 getXxx() 함수 이용

int salary = cs.getInt(1);

 

 

실습

게시글 하나를 표현할 수 있는 VO 객체 생성

BoardVO.java

package biz.board;

import java.util.Date;

public class BoardVO {
	private int seq;
	private String title;
	private String writer;
	private String content;
	private Date regDate;
	
	public int getSeq() {
		return seq;
	}
	public void setSeq(int seq) {
		this.seq = seq;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getRegDate() {
		return regDate;
	}
	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
	
	// 편의성을 위해 toString 함수를 오버라이드 받아 VO객체에 데이터 출력함
	@Override
	public String toString() {
		return "BoardVO [seq=" + seq + ", title=" + title + ", writer=" + writer + ", content=" + content + ", regDate="
				+ regDate + "]";
	}
}

 

DAO 클래스를 이용하여 게시글 내용이 DB에 저장 또는 DB에서 SELECT 되도록 작업함

BoardDAO.java

package biz.board;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import biz.common.JDBCUtil;

public class BoardDAO {
	// connect 객체와 statement 객체가 필요하므로 멤버 변수로 선언
	private Connection conn;
	private PreparedStatement stmt;
	private ResultSet rs;
	
	// SQL 문을 담을 수 있는 변수 선언
	// title과 writer와 content는 실제 유저 입력 값으로,
	// 첫 번째 컬럼 데이터는 primaryKey 데이터 (board에서 가장 큰 숫자 값을 뽑아 더하기 1)
	private static String BOARD_INSERT =
			"insert into board (seq, title, writer, content) values "+
			"((select nvl(max(seq), 0) + 1, from board), ?,?,?)";
	
	// 전체 목록을 SELECT 하기 위한 SQL 문도 필요
	private static String BOARD_LIST = "select * from board";
	
	// 실제 DBMS가 필요할 때 호출되는 함수 선언
	public void insertBoard(BoardVO vo) {
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_INSERT);
			stmt.setString(1,  vo.getTitle());
			stmt.setString(2,  vo.getWriter());
			stmt.setString(3,  vo.getContent());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
	}
	// 전체 게시글 목록을 뽑기 위해서 호출되는 함수 정의
	public List<BoardVO> getBoardList(BoardVO vo){
		List<BoardVO> boardList = new ArrayList<BoardVO>();
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_LIST);
			rs = stmt.executeQuery();
			// while 문 안에 작성했을 경우, 게시글이 없다면 false
			// while 문이 한번 돌때마다 하나의 게시글이라는 의미
			while(rs.next()) {
				BoardVO board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				boardList.add(board);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(rs, stmt, conn);
		}
		return boardList;
	}
}

 

게시글 입력 요청을 위한 Controller 생성

InsertBoardController.java

package controller.board;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import biz.board.BoardDAO;
import biz.board.BoardVO;
import controller.Controller;

public class InsertBoardController implements Controller{
		@Override
		public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
			String title = request.getParameter("title");
			String writer = request.getParameter("writer");
			String content = request.getParameter("content");
			
			// 유저가 입력한 데이터를 VO로 표현하고 VO에 담음
			BoardVO vo = new BoardVO();
			vo.setTitle(title);
			vo.setWriter(writer);
			vo.setContent(content);
			
			// 만들어 놓은 DAO의 함수 호출
			// insertBoard 함수 호출 -> 유저 입력 데이터 전달 -> DB에 저장
			BoardDAO dao = new BoardDAO();
			dao.insertBoard(vo);
			
			// 문자열로 getBoardList.do 화면이 나오도록 리턴
			return "getBoardList.do";
		}
}

 

전체 게시글을 보기위한 요청을 처리하는 Controller

GetBoardListController.java

package controller.board;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import biz.board.BoardDAO;
import biz.board.BoardVO;
import controller.Controller;

public class GetBoardListController implements Controller {
	@Override
	public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
		BoardVO vo = new BoardVO();
		BoardDAO dao = new BoardDAO();
		// DAO가 데이터베이스에서 글을 SELECT하여 리턴시킴
		List<BoardVO> boardList = dao.getBoardList(vo);
		
		// 만들어 놓은 getBoardList 함수를 호출하고 결과를 Request 객체에 담음
		request.setAttribute("boardList", boardList);
		return "getBoardList.jsp";
	}
}

 

이 2개의 Controller를 Mapping에 등록

mappings.put("/insertBoard.do", new InsertBoardController());
mappings.put("/getBoardList.do", new GetBoardListController());

 

로그인이 성공 상태면 텍스트만 보여지는게 아니라 게시글을 쓸 수 있는 화면으로 넘어가게 한다.

LoginController.java 수정

		if(user != null) {
			HttpSession session = request.getSession();
			session.setAttribute("user", user);
//			return "ok.jsp";
			return "getBoardList.do";

 

insertBoard.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>새글 등록</h1>
<hr/>
<form action="insertBoard.do" method="post">
<table border="1">
	<tr>
		<td>title</td>
		<td><input type="text" name="title"/></td>
	</tr>
	<tr>
		<td>writer</td>
		<td><input type="text" name="writer"/></td>
	</tr>
	<tr>
		<td>content</td>
		<!--길게 작성할 수 있게끔 textarea로 작성-->
		<td><textarea name="content" cols="40" rows="10"/>
			</textarea>
		</td>
	</tr>
	<tr>
		<td colspan="2"><input type="submit" value="add"/></td>
	</tr>
</table>
</form>
</body>
</html>

 

게시글 목록 확인 가능한 파일 생성

getBoardList.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h1>board list</h1>
<hr/>
<h3>${user.name } 님 환영합니다. <a href="Logout.do">logout</a></h3>
<table border="1">
	<tr>
		<td>no</td><td>title</td><td>writer</td><td>date</td>
	</tr>
	<c:forEach var="board" items="${boardList }">
		<tr>
			<td>${board.seq }</td>
			<td><a href="getBoard.do?seq=${board.seq }">${board.title }</a></td>
			<td>${board.writer }</td>
			<td>${board.regDate }</td>
		</tr>
	</c:forEach>
</table>
<!-- 새 글을 등록할 수 있는 화면을 링크로 제공 -->
<br/>
<a href="insertBoard.html">add board</a>
</body>
</html>

 

테스트

login.html 실행

DB에 등록된 데이터를 넣고 login 버튼 누르면 board list 페이지로 넘어감

add board 클릭

글을 입력하고 add를 눌렀을 때 board list에 추가되면 됨

 

 

--

사소한 오류는 있었지만 앞에서 나온 오류랑 같은거라 뚝딱하니 멀쩡히 구동된다

 

감동이 있네....