Study Web Development

1월 18일

이전으로

Servlet & JSP

6. 모델 1 방식으로 DB 연동하기

m1_board

UI
  1. 새 JSP 파일 detail.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.board.dao.BoardDAO" %>
<%@ page import="kr.board.vo.BoardVO" %>
<%
	int num = Integer.parseInt(request.getParameter("num"));
	BoardDAO dao = BoardDAO.getInstance();
	BoardVO boardVO = dao.getBoard(num);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 글 상세</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
</head>
<body>
<div class="page-main">
	<h1>게시판 글 상세</h1>
	<ul>
		<li>글 번호 : <%= boardVO.getNum() %></li>
		<li>제목 : <%= boardVO.getTitle() %></li>
		<li>작성자 : <%= boardVO.getName() %></li>
	</ul>
	<hr size="1" width="100%" noshade>
	<p>
		<%= boardVO.getContent() %>
	</p>
	<div class="align-right">
		작성일 : <%= boardVO.getReg_date() %>
		<input type="button" value="수정" onclick="location.href = 'updateForm.jsp?num=<%= boardVO.getNum() %>';">
		<input type="button" value="삭제" onclick="location.href = 'deleteForm.jsp?num=<%= boardVO.getNum() %>';">
		<input type="button" value="목록" onclick="location.href = 'list.jsp';">
	</div>
</div>
</body>
</html>
  1. 새 JSP 파일 updateForm.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.board.dao.BoardDAO" %>
<%@ page import="kr.board.vo.BoardVO" %>
<%
	int num = Integer.parseInt(request.getParameter("num"));
	BoardDAO dao = BoardDAO.getInstance();
	BoardVO board = dao.getBoard(num);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 수정</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
<script type="text/javascript">
	window.onload = function() {
		document.getElementById('update_form').onsubmit = function() {
			let list = document.getElementsByTagName('li');
			for(let i=0;i<list.length;i++) {
				let input = list[i].querySelector('input,textarea');
				input.value = input.value.trim();
				if(!input.value) {
					let word = list[i].querySelector('label').textContent;
					let post = (word.charCodeAt(word.length-1) - ''.charCodeAt(0)) % 28 > 0 ? '' : '';
					alert(word + post + ' 입력하세요!');
					input.focus();
					return false;
				}
			}
		};
	};
</script>
</head>
<body>
<div class="page-main">
	<h1>글 수정</h1>
	<form id="update_form" action="update.jsp" method="post">
		<input type="hidden" name="num" value="<%= board.getNum() %>"> <%-- 회원 번호와 달리 글 번호는 세션에 저장하지 않으므로 type="hidden"으로 전달 --%>
		<ul>
			<li>
				<label for="title">제목</label>
				<input type="text" name="title" id="title" value="<%= board.getTitle() %>" size="30" maxlength="50">
			</li>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" value="<%= board.getName() %>" size="10" maxlength="10">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" size="10" maxlength="12"> <%-- 비밀번호는 수정 대상이 아니라, 인증용 --%>
				* 글 등록시 입력한 비밀번호
			</li>
			<li>
				<label for="content">내용</label>
				<textarea rows="5" cols="40" name="content" id="content"><%= board.getContent() %></textarea> <%-- <textarea> 태그의 미리보기는 (value 속성이 아니라) 시작 태그와 끝 태그 사이에, 공백 없이 명시 --%>
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="글 수정">
			<input type="button" value="이전" onclick="history.go(-1);">
			<input type="button" value="목록" onclick="location.href = 'list.jsp';">
		</div>
	</form>
</div>
</body>
</html>
  1. 새 JSP 파일 update.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.board.dao.BoardDAO" %>
<%@ page import="kr.board.vo.BoardVO" %>
<%
	// 전송된 데이터 인코딩 처리
	request.setCharacterEncoding("UTF-8");
%>
<jsp:useBean id="boardVO" class="kr.board.vo.BoardVO"/>
<jsp:setProperty property="*" name="boardVO"/>
<%
	BoardDAO dao = BoardDAO.getInstance();
	// 비밀번호 인증을 수행하기 위해 글 번호를 전달하고 한 건의 레코드 정보를 자바빈에 담아 반환
	BoardVO db_board = dao.getBoard(boardVO.getNum());
	boolean check = false;
	if(db_board!=null) {
		check = db_board.isCheckedPassword(boardVO.getPasswd());	
	}
	
	if(check) { // 인증 성공
		boardVO.setIp(request.getRemoteAddr());
		dao.update(boardVO);
%>
	<script type="text/javascript">
		alert('글 수정을 완료했습니다.');
		location.href = 'list.jsp';
	</script>
<%
	}
	else { // 인증 실패
%>
	<script type="text/javascript">
		alert('비밀번호 불일치!');
		history.go(-1);
	</script>
<%
	}
%>

m1_product

프로젝트 생성 및 설정
  1. 새 다이나믹 웹 프로젝트를 생성하여 프로젝트명에 m1_product 입력 후 Next-Next-Generate web.xml depolyment descriptor 선택 후 Finish
  2. 프로젝트를 오른쪽 클릭하여 Build Path-Configure Build Path... 선택하고 Libraries 탭에서 JRE System Library를 선택 후 Edit...에서 JavaSE-1.8(jre)로 변경
  3. 프로젝트를 오른쪽 클릭하여 Properties 선택하고 좌측 목록에서 Project Facets 선택 후 Java의 Version을 1.8로 변경
  4. C:\javaWork\apps에서 ojdbc8.jar를 복사하여 C:\javaWork\workspace_jsp\m1_product\src\main\webapp\WEB-INF\lib에 붙여넣기
  5. m1_board 프로젝트의 webapp/META-INF 폴더에서 context.xml을 복사하여 m1_product 프로젝트의 webapp/META-INF 폴더에 붙여넣기
  6. m1_board 프로젝트의 webapp 폴더에서 css 폴더를 복사하여 m1_product 프로젝트의 webapp 폴더에 붙여넣기
  7. m1_product 프로젝트의 webapp 폴더 오른쪽 클릭 후 새 폴더 js 생성하고 jquery-3.6.0.min.js 파일을 해당 폴더로 이동
  8. src/main/webapp 폴더 오른쪽 클릭하고 새 폴더 sql 생성 후 table.sql 생성
CREATE TABLE sproduct(
	num NUMBER PRIMARY KEY,
	name VARCHAR2(30) NOT NULL,
	price NUMBER NOT NULL,
	stock NUMBER NOT NULL,
	origin VARCHAR2(30) NOT NULL,
	content CLOB NOT NULL,
	reg_date DATE DEFAULT SYSDATE NOT NULL
);

CREATE SEQUENCE sproduct_seq;
  1. src/main/java 오른쪽 클릭하여 새 패키지 kr.util 생성하고 PagingUtil.java를 해당 패키지로 이동
자바빈
  1. src/main/java 오른쪽 클릭하여 새 패키지 kr.product.vo 생성하고 새 클래스 ProductVO 생성
package kr.product.vo;

import java.sql.Date;

public class ProductVO {
	private int num; // 상품 번호
	private String name; // 상품명
	private int price; // 가격
	private int stock; // 재고
	private String origin; // 원산지
	private String content; // 상품 설명
	private Date reg_date; // 등록일
	
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public int getStock() {
		return stock;
	}
	public void setStock(int stock) {
		this.stock = stock;
	}
	public String getOrigin() {
		return origin;
	}
	public void setOrigin(String origin) {
		this.origin = origin;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
}
DAO
  1. src/main/java 오른쪽 클릭하여 새 패키지 kr.product.dao 생성하고 새 클래스 ProductDAO 생성
package kr.product.dao;

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

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import kr.product.vo.ProductVO;

public class ProductDAO {
	// 싱글턴 패턴
	private static ProductDAO instance = new ProductDAO();
	public static ProductDAO getInstance() {
		return instance;
	};
	private ProductDAO() {}
	
	// context.xml에서 설정 정보를 읽어들여 커넥션 풀로부터 커넥션을 할당받음
	private Connection getConnection() throws Exception {
		Context initCtx = new InitialContext();
		DataSource ds = (DataSource)initCtx.lookup("java:comp/env/jdbc/xe");
		return ds.getConnection();
	}
	
	// 자원 정리
	private void executeClose(ResultSet rs, PreparedStatement pstmt, Connection conn) {
		if(rs!=null) try {rs.close();} catch(SQLException e) {}
		if(pstmt!=null) try {pstmt.close();} catch(SQLException e) {}
		if(conn!=null) try {conn.close();} catch(SQLException e) {}
	}
	
	// 상품 저장
	public void insert(ProductVO vo) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "INSERT INTO sproduct (num, name, price, stock, origin, content) "
				+ "VALUES (sproduct_seq.NEXTVAL, ?, ?, ?, ?, ?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, vo.getName());
			pstmt.setInt(2, vo.getPrice());
			pstmt.setInt(3, vo.getStock());
			pstmt.setString(4, vo.getOrigin());
			pstmt.setString(5, vo.getContent());
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			executeClose(null, pstmt, conn);
		}
	}
	
	// 상품의 총 갯수
	public int getCount() throws Exception {
		int count = 0;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "SELECT COUNT(*) FROM sproduct";
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				count = rs.getInt(1);
			}
		}
		catch(Exception	e) {
			throw new Exception(e);
		}
		finally {
			executeClose(rs, pstmt, conn);
		}
		
		return count;
	}
	
	// 상품 목록
	public List<ProductVO> getList(int startRow, int endRow) throws Exception {
		List<ProductVO> list = null;
		
		Connection conn =  null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "SELECT * FROM (SELECT sp.*, ROWNUM AS rnum "
				+ "FROM (SELECT * FROM sproduct ORDER BY num DESC) sp) "
				+ "WHERE rnum >= ? AND rnum <= ?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, startRow);
			pstmt.setInt(2, endRow);
			rs = pstmt.executeQuery();
			list = new ArrayList<ProductVO>();
			while(rs.next()) {
				ProductVO vo = new ProductVO();
				vo.setNum(rs.getInt("num"));
				vo.setName(rs.getString("name"));
				vo.setPrice(rs.getInt("price"));
				vo.setStock(rs.getInt("stock"));
				vo.setOrigin(rs.getString("origin"));
				vo.setReg_date(rs.getDate("reg_date"));
				list.add(vo);
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			executeClose(rs, pstmt, conn);
		}
		
		return list;
	}
	
	// 상품 상세 정보
	public ProductVO getProduct(int num) throws Exception {
		ProductVO vo = null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "SELECT * FROM sproduct WHERE num=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, num);
			rs = pstmt.executeQuery();
			if(rs.next()) {
				vo = new ProductVO();
				vo.setNum(num);
				vo.setName(rs.getString("name"));
				vo.setPrice(rs.getInt("price"));
				vo.setStock(rs.getInt("stock"));
				vo.setOrigin(rs.getString("origin"));
				vo.setContent(rs.getString("content"));
				vo.setReg_date(rs.getDate("reg_date"));
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			executeClose(rs, pstmt, conn);
		}
		
		return vo;
	}
	
	// 상품 정보 수정
	public void update(ProductVO vo) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "UPDATE sproduct SET name=?, price=?, stock=?, origin=?, content=? WHERE num=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, vo.getName());
			pstmt.setInt(2, vo.getPrice());
			pstmt.setInt(3, vo.getStock());
			pstmt.setString(4, vo.getOrigin());
			pstmt.setString(5, vo.getContent());
			pstmt.setInt(6, vo.getNum());
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			executeClose(null, pstmt, conn);
		}
	}
	
	// 상품 정보 삭제
	public void delete(int num) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			conn = getConnection();
			sql = "DELETE FROM sproduct WHERE num=?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, num);
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			executeClose(null, pstmt, conn);
		}
	}
}
UI
  1. webapp 폴더 오른쪽 클릭 후 새 폴더 views 생성하고 새 JSP 파일 writeForm.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품 등록</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
</head>
<body>
<div class="page-main">
	<h1>상품 등록</h1>
	<form action="write.jsp" method="post">
		<ul>
			<li>
				<label for="name">상품명</label>
				<input type="text" name="name">
			</li>
			<li>
				<label for="price">가격</label>
				<input type="number" name="price" min="0">
			</li>
			<li>
				<label for="stock">재고</label>
				<input type="number" name="stock" min="0">
			</li>
			<li>
				<label for="origin">원산지</label>
				<input type="text" name="origin">
			</li>
			<li>
				<label for="content">상품 설명</label>
				<textarea rows="5" cols="40" name="content"></textarea>
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="등록">
			<input type="button" value="목록" onclick="location.href = 'list.jsp';">
		</div>
	</form>
</div>
<script type="text/javascript" src="<%= request.getContextPath() %>/js/validateLength.js"></script>
<script type="text/javascript">
	document.querySelector('form').onsubmit = validateSubmit;
	
	let txts = document.querySelectorAll('input[type="text"]');
	for(let i=0;i<txts.length;i++) {
		txts[i].onkeyup = function() {
			while(getBytesLength(this.value)>30) {
				this.value = this.value.slice(0, -1);
			}
		};
	}
</script>
</body>
</html>
  1. js 폴더에 새 JavaScript 파일 validateLength.js 생성
function validateSubmit() {
	let list = document.getElementsByTagName('li');
	for(let i=0;i<list.length;i++) {
		let input = list[i].querySelector('input,textarea');
		input.value = input.value.trim();
		if(!input.value) {
			let word = list[i].querySelector('label').textContent;
			let post = (word.charCodeAt(word.length-1) - ''.charCodeAt(0)) % 28 > 0 ? '' : '';
			alert(word + post + ' 입력하세요!');
			input.focus();
			return false;
		}
	}
}

function getBytesLength(str) {
    let bytes = 0;
    for(let i=0;i<str.length;i++) {
        let unicode = str.charCodeAt(i);
        bytes += unicode >> 11 ? 3 : (unicode >> 7 ? 2 : 1); // 2^11=2048로 나누었을 때 몫이 있으면 3bytes, 그보다 작은 수이면서 2^7=128로 나누었을 때 몫이 있으면 2bytes, 그 외에는 1byte
    }
    return bytes;
}
  1. 새 JSP 파일 write.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.product.dao.ProductDAO" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<jsp:useBean id="vo" class="kr.product.vo.ProductVO"/>
<jsp:setProperty property="*" name="vo"/>
<%
	ProductDAO dao = ProductDAO.getInstance();
	dao.insert(vo);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품 등록 완료</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
</head>
<body>
<div class="page-main">
	<h1>상품 등록 완료</h1>
	<div class="result-display">
		<div class="align-center">
			상품 등록이 완료되었습니다.<br>
			<input type="button" value="목록" onclick="location.href = 'list.jsp';">
			<input type="button" value="추가" onclick="location.href = 'writeForm.jsp';">
		</div>
	</div>
</div>
</body>
</html>

다음으로