반응형

DB commit 하지 않으면 데이터가 안넘어갑니다. 꼭 확인해주세요

 

 

 

JDBC를 활용해서 방명록을 작성해보겠습니다.

 

 

 

 

 

흐름도는 대략적으로 이렇습니다.

 

 

Data Binding(데이터 연결) request

 

왼쪽은 전부 User의 요청처리이다. (url로 요청을 하게 된다) ->

Servlet이 각각의 요청을 처리하는 객체로 받아준다.

 


 

환경설정 세팅

 

 

 

템플릿을 저장해보자

 

 

 

 

DBBase.war
2.05MB

 

 

 

 

 

 

 

 

Import시 적용 완료

 

 

 


 

 

 

 

 

 

 

SQL 작성

-- 일련번호 관리하는 객체

create sequence seq_visit_idx

-- 방명록 테이블

create table visit
(
	idx     int,		               -- 일련번호
	name    varchar2(100)  not null,   -- 작성자
	content varchar2(2000) not null,   -- 내용
	pwd     varchar2(100)  not null,   -- 비밀번호
	ip      varchar2(100)  not null,   -- 아이피
	regdate date                       -- 작성일자
)

-- 기본키

alter table visit
	add constraint pk_visit_idx primary key(idx);
	
-- sample data

insert into visit values(seq_visit_idx.nextVal,
						'일길동',
						'내가 1등이네',
						'1234',
						'192.168.219.170',
						sysdate
						);

insert into visit values(seq_visit_idx.nextVal,
						'이길동',
						'뭐여 언제 1등가져감',
						'1234',
						'192.168.219.170',
						sysdate
						);
						
-- idx 내림차순 (최신글 맨 꼭대기에 올리겠다)

select * from visit order by idx desc;

 

 

 

 

 

 

Getter Setter 작성

package db.vo;

public class VisitVo {

	int idx;
	String name;
	String content;
	String pwd;
	String ip;
	String regdate;
	
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public String getRegdate() {
		return regdate;
	}
	public void setRegdate(String regdate) {
		this.regdate = regdate;
	}
	
}

 

 

 

Dao 생성하기

package 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 db.vo.VisitVo;
import service.DBService;

public class VisitDao {

	// single-ton pattern : 객체 1개만 생성해서 사용하자
	static VisitDao single = null;

	public static VisitDao getInstance() {
		// 없으면 생성해라
		if (single == null) {
			single = new VisitDao();
		}
		return single;
	}
	// 외부에서 객체생성하지 말아라...
	private VisitDao() {

	}
	
	
	// 테이블 목록 조회
	public List<VisitVo> selectList() {
		List<VisitVo> list = new ArrayList<VisitVo>();

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from visit order by idx desc";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			while (rs.next()) {
				
				// 1. 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				VisitVo vo = new VisitVo();

				// rs가 가리키는 레코드값을 VO에 넣는다.
				vo.setIdx(rs.getInt("idx"));
				vo.setName(rs.getString("name"));
				vo.setContent(rs.getString("content"));
				vo.setPwd(rs.getString("pwd"));
				vo.setIp(rs.getString("ip"));
				vo.setRegdate(rs.getString("regdate"));
				// ArrayList에 추가
				list.add(vo);

			} //end:while

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;
	}
	
}

 

 

 

Servlet 생성하기

package action;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

import dao.VisitDao;
import db.vo.VisitVo;

/**
 * Servlet implementation class VisitListAction
 */
@WebServlet("/visit/list.do")
public class VisitListAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 방명록 데이터 가져오기
		List<VisitVo> list = VisitDao.getInstance().selectList();
		
		// request binding
		request.setAttribute("list", list);
		
		// Dispatcher형식으로 호출
		String forward_page = "visit_list.jsp";
		RequestDispatcher disp = request.getRequestDispatcher(forward_page);
		disp.forward(request, response);

	}

}

 

 

 

JSP 파일 생성

(너 출력하는거 자신있지 JSP, 그러니까 너가 출력을 하자 foward_page = "visit_list.jsp")

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- JSTL Library -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>박정환 Story</title>
<%-- 현재 컨텍스트 경로 : ${ pageContext.request.contextPath } --%>
<link rel="stylesheet" href="../css/visit.css">
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
	<div id="box">
		<h1 id="title">여러분의 방문을 환영합니다.</h1>

		<div style="margin-bottom: 10px">
			<input class="btn btn-primary" type="button" value="글쓰기">
		</div>

		<!-- 내용이 없을 경우 -->
		<c:if test="${ empty requestScope.list }">
			<div id="empty_msg">등록된 게시물이 없습니다.</div>
		</c:if>

		<!-- 내용 -->
		<!-- for(VisitVo vo : list) 동일 -->
		<!-- 글자 자동정렬 Ctrl + Shift + F -->
		<c:forEach var="vo" items="${ requestScope.list }">
		<form class="form-inline">
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h4><b>${ vo.name }</b>님의 글 :</h4>
				</div>
				<div class="panel-body">
					<div class="mycommon content">${ vo.content }</div>
					<div class="mycommon regdate"><b>작성일자 : </b>${ fn:substring(vo.regdate,0,16) }</div>
					<div class="mycommon pwd">비밀번호 : 
						<input class="form-control" type = "password" id="pwd">
						<input class="btn btn-info" type = "button" value="수정">
						<input class="btn btn-danger" type = "button" value="삭제">
					</div>
				</div>
			</div>
		</form>
		</c:forEach>
	</div>

</body>
</html>

 

 

 

CSS 생성하기

@charset "UTF-8";

@font-face {
    font-family: 'Pretendard-Regular';
    src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff');
    font-weight: 400;
    font-style: normal;
}

* {
    font-family: "Pretendard-Regular";
}

#box {
	width: 50vw;
	height: 15vw;
	
	margin: auto;
	margin-top: 30px;
}

#title {
	text-align: center;
	font-size: 28px;
	font-weight: bold;
	color: #323a4e;
	
	margin-bottom: 60px
}

#empty_msg {
	text-align: center;
	color: red;
	
	font-weight: bold;
	font-size: 20px;
	
	margin-top: 100px;
}

.mycommon {
	margin: 5px;
	padding: 5px;	
	border: 1px solid #eeeeee;
	box-shadow: 1px 1px 3px #eeeeee;
	border-radius: 10px;
}

.content {
	min-height: 60px;
	
	font-size: 16px;
}

.pwd {
	font-weight: bold;
}

 

 

 

 

 

모든 형식은 일관성 있게 해야한다. 그렇기 때문에 Form관련 view 파일 문서는 바로 JSP로 연결시켜줘도 되지만, Servlet을 통해서 forward 경로로 JSP가 출력할 수 있게 만든다.

package action;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Servlet implementation class VisitInsertFormAction
 */
@WebServlet("/visit/insert_form.do")
public class VisitInsertFormAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// Dispatcher형식으로 호출
		String forward_page = "visit_insert_form.jsp";
		RequestDispatcher disp = request.getRequestDispatcher(forward_page);
		disp.forward(request, response);

	}

}

 

 

 

 

내가 프로젝트에서 파일을 열때 가장 기본적으로 메인화면을 고정적으로 띄우고 싶을 때

 

 

 

 

JSP 생성하기

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<style type="text/css">
@font-face {
    font-family: 'MabinogiClassicR';
    src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_2207-01@1.0/MabinogiClassicR.woff2') format('woff2');
    font-weight: normal;
    font-style: normal;
}

* {
    font-family: "MabinogiClassicR";
}

#title {
	text-align: center;
	font-size: 28px;
	
	margin-bottom: 60px
}

#box {
	width: 600px;
	margin: auto;
	margin-top: 100px;
}

textarea {
	resize: none;
}

th {
	vertical-align: middle !important;
	width: 15%;
}
</style>

<script type="text/javascript">

	function send(f) {
		
		// 입력값 검증
		let name = f.name.value.trim();
		let content = f.content.value.trim();
		let pwd = f.pwd.value.trim();
		
		if(name=='') {
			alert("작성자명을 입력하세요!")
			f.name.value = "";
			f.name.focus();
			return;
		}
		if(content=='') {
			alert("내용을 입력하세요!")
			f.content.value = "";
			f.content.focus();
			return;
		}
		if(pwd=='') {
			alert("비밀번호를 입력하세요!")
			f.pwd.value = "";
			f.pwd.focus();
			return;
		}
		
		f.method = "POST";
		f.action = "insert.do";
		f.submit();
	}

</script>

</head>
<body>
	<form>
		<div id="box">
			<h1 id="title">여러분의 방문을 환영합니다.</h1>
			<!-- Ctrl + Shift + F -->
			<div class="panel panel-primary">
				<div class="panel-heading"><h4>글쓰기</h4></div>
				<div class="panel-body">
					<table class="table">
						<tr>
							<th>작성자</th>
							<td><input class="form-control" name="name" required="required" autofocus></td>
						</tr>
						
						<tr>
							<th>내용</th>
							<td>
								<textarea class="form-control" rows="5" name="content" required="required"></textarea>
							</td>
						</tr>
						
						<tr>
							<th>비밀번호</th>
							<td><input class="form-control" type="password" name="pwd" required="required"></td>
						</tr>
						
						<tr>
							<td colspan="2" align="center">
								<input class="btn btn-success" type="button" value="목록보기"
									onclick="location.href='list.do'">
								<input class="btn btn-primary" type="button" value="글올리기"
									onclick="send(this.form)">
							</td>
						</tr>
					</table>
				</div>
			</div>
		</div>
	</form>
</body>
</html>

 

 

 

POST 방식으로 넣었지만 F12 네트워크 탭을 통해서 무슨 정보가 넘어갔는지 확인이 가능하다.

 

 

 

insert JSP 작성하기

package action;

import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;

import dao.VisitDao;
import db.vo.VisitVo;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class VisitInsertAction
 */
@WebServlet("/visit/insert.do")
public class VisitInsertAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, // client -> server로 들어오는정보 처리
			HttpServletResponse response) // server -> client로 응답처리하는 객체
			throws ServletException, IOException {
		
		// /visit/insert.do?name=홍길동&content=안녕&pwd=1234
		
		// 0. 수신인코딩 설정
		request.setCharacterEncoding("utf-8");
		
		// 1. parameter(전달인자) 받기
		String name = request.getParameter("name");
		String content = request.getParameter("content").replaceAll("\n", "<br>");
		String pwd = request.getParameter("pwd");
		
		// 2. ip 정보 받기
		String ip = request.getRemoteAddr();
		
		// 3. VisitVo 포장
		// vo에서 오버로드 된 생성자 새로 추가
		VisitVo vo = new VisitVo(name, content, pwd, ip);
		
		// 4. DBinsert
		int res = VisitDao.getInstance().insert(vo);
		
		// 5. 목록보기
		response.sendRedirect("list.do");
	}
}

 

 

 

Vo 생성자를 만들어서 생성자를 오버로드 해서 만들어야 한다.

// 오버로드 된 생성자를 만들면, 무조건 기본 생성자를 만들어야 한다. (매개변수 인자를 안넣은 곳이 있기 때문이다)
public VisitVo(String name, String content, String pwd, String ip) {
    super();
    this.name = name;
    this.content = content;
    this.pwd = pwd;
    this.ip = ip;
}

public VisitVo() {
    // TODO Auto-generated constructor stub
}

 

 

 

 

Dao에 insert() 추가

	public int insert(VisitVo vo) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		//                                                           1 2 3 4 <- pstmt index
		String sql = "insert into visit values(seq_visit_idx.nextVal,?,?,?,?,sysdate)";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setString(1, vo.getName());
			pstmt.setString(2, vo.getContent());
			pstmt.setString(3, vo.getPwd());
			pstmt.setString(4, vo.getIp());

			// 4. DB insert
			res = pstmt.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:insert()

 

삭제하기

 

 

삭제 기능 구현

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- JSTL Library -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>박정환 Story</title>
<%-- 현재 컨텍스트 경로 : ${ pageContext.request.contextPath } --%>
<link rel="stylesheet" href="../css/visit.css">
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
	
<script type="text/javascript">
	function del(f) {
		
		let pwd = f.pwd.value; // 게시물 생성 당시에 지정한 비밀번호
		let c_pwd = f.c_pwd.value.trim(); // 내가 입력한 비밀번호
		
		if(pwd != c_pwd) {
			alert("비밀번호가 일치하지 않습니다.");
			f.c_pwd.value="";
			f.c_pwd.focus();
			return;
		}
		// 데이터가 삭제될 때는 정말 삭제하시겠냐고 한 번더 물어보는 문구가 필요하다.
		// 삭제확인 : 확인(true) 취소(false)
		if(confirm("정말 삭제하시겠습니까?")==false) {
			retutn;
		}
		
		// 삭제요청하는 경로로 보내기
		// f.action="delete.do";
		// 삭제할 게시물 idx를 보내야 한다.
		// f.submit(); 폼submit을 하면 form안에 있는 모든 값이 넘어간다.
		
		// 방법2 : location 전송(선택적으로 parameter 전송하는 방법)
		location.href = "delete.do?idx=" + f.idx.value;
		
	}
</script>
</head>
<body>
	<div id="box">
		<h1 id="title">여러분의 방문을 환영합니다.</h1>

		<div style="margin-bottom: 10px">
			<input class="btn btn-primary" type="button" value="글쓰기"
			onclick="location.href='insert_form.do'">
		</div>

		<!-- 내용이 없을 경우 -->
		<c:if test="${ empty requestScope.list }">
			<div id="empty_msg">등록된 게시물이 없습니다.</div>
		</c:if>

		<!-- 내용 -->
		<!-- for(VisitVo vo : list) 동일 -->
		<!-- 글자 자동정렬 Ctrl + Shift + F -->
		<c:forEach var="vo" items="${ requestScope.list }">
		<form class="form-inline">
			<!-- 화면상에 안보임(새로 배운 내용) 보안에 가장 취약한 방법 -->		
			<input type="hidden" name="pwd" value="${ vo.pwd }">
			<!-- 삭제해야할 idx 게시물 번호도 hidden으로 보낸다 (임시방편) -->
			<input type="hidden" name="idx" value="${ vo.idx }">
			
			<div class="panel panel-primary">
				<div class="panel-heading">
					<h4><b>${ vo.name }</b>님의 글 : ${ vo.ip }</h4>
				</div>
				<div class="panel-body">
					<div class="mycommon content">${ vo.content }</div>
					<div class="mycommon regdate"><b>작성일자 : </b>${ fn:substring(vo.regdate,0,16) }</div>
					<div class="mycommon pwd">비밀번호${ vo.pwd } : 
						<!-- c_pwd 수정 -->		
						<input class="form-control" type = "password" id="c_pwd">
						<input class="btn btn-info" type = "button" value="수정">
						<!-- delete onclick 추가 -->		
						<input class="btn btn-danger" type = "button" value="삭제" onclick="del(this.form);">
					</div>
				</div>
			</div>
		</form>
		</c:forEach>
	</div>

</body>
</html>

 

 

 

delete.do Servlet 작성

package action;

import java.io.IOException;

import dao.VisitDao;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class VisitDeleteAction
 */
@WebServlet("/visit/delete.do")
public class VisitDeleteAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// /visit/delete.do?idx=21
		
		// 삭제할 idx 수신(문자열 정수로 변환)
		// getParamete로 받으면 무조건 String 타입으로 받아진다.
		int idx = Integer.parseInt(request.getParameter("idx"));
		
		// DB 삭제
		int res = VisitDao.getInstance().delete(idx);
		
		// 목록보기(다시 메인 화면으로 돌아가라)
		response.sendRedirect("list.do");

	}
}

 

 

 

 

Dao에서 delete()에 관련된 메서드 만들기

	public int delete(int idx) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		// 테이블안에 있는 데이터 삭제하는 SQL문 사용
		String sql = "delete from visit where idx=?";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setInt(1, idx);

			// 4. DB delete
			res = pstmt.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:delete()

 

 

 

SQL에서 view 생성하기(글 삭제시 No번호가 삭제되어 정렬되는 테이블 지정)

-- view로 생성

create or replace view visit_view
as
select rownum as no, v.*
from (select * from visit order by idx desc) v;

select * from visit_view

 

 

 

Dao에서 insert() 수정

// 테이블 목록 조회
	public List<VisitVo> selectList() {
		List<VisitVo> list = new ArrayList<VisitVo>();

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from visit_view";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			while (rs.next()) {
				
				// 1. 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				VisitVo vo = new VisitVo();

				// rs가 가리키는 레코드값을 VO에 넣는다.
				vo.setIdx(rs.getInt("idx"));
				vo.setName(rs.getString("name"));
				vo.setContent(rs.getString("content"));
				vo.setPwd(rs.getString("pwd"));
				vo.setIp(rs.getString("ip"));
				vo.setRegdate(rs.getString("regdate"));
				// ArrayList에 추가
				list.add(vo);

			} //end:while

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return list;
	}

 

 

 

Vo에서 int no 추가 (view에 no 컬럼 추가되었기 때문에)

public class VisitVo {

	int idx;
	int no;
	String name;
	String content;
	String pwd;
	String ip;
	String regdate;
	// 오버로드 된 생성자를 만들면, 무조건 기본 생성자를 만들어야 한다. (매개변수 인자를 안넣은 곳이 있기 때문이다)
	public VisitVo(String name, String content, String pwd, String ip) {
		super();
		this.name = name;
		this.content = content;
		this.pwd = pwd;
		this.ip = ip;
	}
	
	public VisitVo() {
		// TODO Auto-generated constructor stub
	}
	
	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

 

 

 

Dao insert()에 값추가

				// rs가 가리키는 레코드값을 VO에 넣는다.
				vo.setNo(rs.getInt("no"));
				vo.setIdx(rs.getInt("idx"));
				vo.setName(rs.getString("name"));
				vo.setContent(rs.getString("content"));
				vo.setPwd(rs.getString("pwd"));
				vo.setIp(rs.getString("ip"));
				vo.setRegdate(rs.getString("regdate"));
				// ArrayList에 추가
				list.add(vo);

 

 

 

list에서 수정(no value 추가)

		// 방법2 : location 전송(선택적으로 parameter 전송하는 방법)
		location.href = "delete.do?idx=" + f.idx.value + "&no=" + f.no.value;
		
	}
</script>
</head>
<body>
	<div id="box">
		<h1 id="title">여러분의 방문을 환영합니다.</h1>

		<div style="margin-bottom: 10px">
			<input class="btn btn-primary" type="button" value="글쓰기"
			onclick="location.href='insert_form.do'">
		</div>

		<!-- 내용이 없을 경우 -->
		<c:if test="${ empty requestScope.list }">
			<div id="empty_msg">등록된 게시물이 없습니다.</div>
		</c:if>

		<!-- 내용 -->
		<!-- for(VisitVo vo : list) 동일 -->
		<!-- 글자 자동정렬 Ctrl + Shift + F -->
		<c:forEach var="vo" items="${ requestScope.list }">
		<form class="form-inline">
			<!-- 화면상에 안보임(새로 배운 내용) 보안에 가장 취약한 방법 -->		
			<input type="hidden" name="pwd" value="${ vo.pwd }">
			<!-- 삭제해야할 idx 게시물 번호도 hidden으로 보낸다 (임시방편) -->
			<input type="hidden" name="idx" value="${ vo.idx }">
			<!-- 현페이지에서 다른페이지에서 정보를 넘겨줄때 정보를 유지하는 기술 -->
			<input type="hidden" name="no"  value="${ vo.no }">
			
			<div class="panel panel-primary" id="p_${ vo.no }">
				<div class="panel-heading">
					<h4><b>${ vo.name }</b>님의 글 : ${ vo.ip }</h4>
				</div>

 

 

 

delete.do 변경

@WebServlet("/visit/delete.do")
public class VisitDeleteAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// /visit/delete.do?idx=21
		
		// 삭제할 idx 수신(문자열 정수로 변환)
		// getParamete로 받으면 무조건 String 타입으로 받아진다.
		int idx = Integer.parseInt(request.getParameter("idx"));
		String no = request.getParameter("no"); // 삭제할 글의 순서
		
		// DB 삭제
		int res = VisitDao.getInstance().delete(idx);
		
		
		// 목록보기(다시 메인 화면으로 돌아가라)
		response.sendRedirect("list.do#p_"+ no);

	}
}

 

 

 

 

수정하기

(수정하기가 완료되면, 수정된 화면이 나오게 해야함)

list 메인 수정

    <!-- c_pwd 수정 -->		
    <input class="form-control" type = "password" id="c_pwd">
    <input class="btn btn-info" type = "button" value="수정" onclick="modify(this.form)">
	function modify_form(f) {
		
		let pwd = f.pwd.value;
		let c_pwd = f.c_pwd.value.trim();
		
		if(pwd != c_pwd) {
			alert("수정할 게시물의 비밀번호가 일치하지 않습니다.");
			f.c_pwd.value="";
			f.c_pwd.focus();
			return;
		}
		
		if(confirm("정말 수정하시겠습니까?")==false) {
			return;
		}
		
		// 수정폼 띄우기(요청)
		location.href = "modify_form.do?idx=" + f.idx.value + "&no=" + f.no.value;
	}

 

 

 

modify_form Servlet 작성하기

package action;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Servlet implementation class VisitModifyFormAction
 */
@WebServlet("/visit/modify_form.do")
public class VisitModifyFormAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// Dispatcher형식으로 호출
		String forward_page = "visit_modify_form.jsp";
		RequestDispatcher disp = request.getRequestDispatcher(forward_page);
		disp.forward(request, response);
	}

}

 

 

 

JSP visit_modify_form 작성하기

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

<style type="text/css">
@font-face {
    font-family: 'MabinogiClassicR';
    src: url('https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_2207-01@1.0/MabinogiClassicR.woff2') format('woff2');
    font-weight: normal;
    font-style: normal;
}

* {
    font-family: "MabinogiClassicR";
}

#title {
	text-align: center;
	font-size: 28px;
	
	margin-bottom: 60px
}

#box {
	width: 600px;
	margin: auto;
	margin-top: 100px;
}

textarea {
	resize: none;
}

th {
	vertical-align: middle !important;
	width: 15%;
}
</style>

<script type="text/javascript">

	function send(f) {
		
		// 입력값 검증
		let name = f.name.value.trim();
		let content = f.content.value.trim();
		let pwd = f.pwd.value.trim();
		
		if(name=='') {
			alert("작성자명을 입력하세요!")
			f.name.value = "";
			f.name.focus();
			return;
		}
		if(content=='') {
			alert("내용을 입력하세요!")
			f.content.value = "";
			f.content.focus();
			return;
		}
		if(pwd=='') {
			alert("비밀번호를 입력하세요!")
			f.pwd.value = "";
			f.pwd.focus();
			return;
		}
        
        if(confirm("정말 수정하시겠습니까?")==false) {
			location.href=""; // 현재 자신의 페이지를 호출
			return;
		}
		
		f.method = "GET";
		f.action = "modify.do";// 전송대상(VisitInsertAction)
		f.submit();
	}

</script>

</head>
<body>
	<form>
		<div id="box">
			<h1 id="title">나의 글을 수정합니다.</h1>
			<!-- Ctrl + Shift + F -->
			<div class="panel panel-primary">
				<div class="panel-heading"><h4>수정하기</h4></div>
				<div class="panel-body">
					<table class="table">
						<tr>
							<th>작성자</th>
							<td><input class="form-control" name="name" required="required" value="${ requestScope.vo.name }" autofocus></td>
						</tr>
						
						<tr>
							<th>내용</th>
							<td>
								<textarea class="form-control" rows="5" name="content">${ vo.content }</textarea>
							</td>
						</tr>
						
						<tr>
							<th>비밀번호</th>
							<td><input class="form-control" type="password" name="pwd" value="${ vo.pwd }"></td>
						</tr>
						
						<tr>
							<td colspan="2" align="center">
								<input class="btn btn-success" type="button" value="목록보기"
									onclick="location.href='list.do'">
								<input class="btn btn-primary" type="button" value="수정하기"
									onclick="send(this.form)">
							</td>
						</tr>
					</table>
				</div>
			</div>
		</div>
	</form>
</body>
</html>

 

 

 

form Servlet 수정하기

package action;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

import dao.VisitDao;
import db.vo.VisitVo;

/**
 * Servlet implementation class VisitModifyFormAction
 */
@WebServlet("/visit/modify_form.do")
public class VisitModifyFormAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 수정할 게시물의 idx 받는다.
		int idx = Integer.parseInt(request.getParameter("idx"));
		
		// idx에 해당되는 게시물 1건 얻어오기
		VisitVo vo = VisitDao.getInstance().selectOne(idx);
		
		// textarer \n기능처리 : content <br> -> \n 변환
		String content = vo.getContent().replaceAll("<br>", "\n");

		// request binding(JSP에게 vo의 데이터를 넘겨줘야 하기 때문에 setAttribute 한다)
		request.setAttribute("vo", vo);
		
		// Dispatcher형식으로 호출
		String forward_page = "visit_modify_form.jsp";
		RequestDispatcher disp = request.getRequestDispatcher(forward_page);
		disp.forward(request, response);
	}

}

 

 

 

Dao selectOne() 작성하기

// 하나의 정보만 가져올 때 (where 사용해서 ex)deptno=10)
	public VisitVo selectOne(int idx) {
		VisitVo vo = null;

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		String sql = "select * from visit_view where idx=?";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setInt(1, idx);

			// 4. ResultSet 얻어오기(킵해놨던 sql문 출력하기)
			rs = pstmt.executeQuery();

			// while문을 사용해도 되지만, 공회전이 1회더 발생한다.
			if (rs.next()) {
				// 1. rs가 가리키는 레코드의 값을 읽어온다
				

				// 2. 저장객체 생성 -> 레코드에서 읽은 값을 넣는다.
				vo = new VisitVo();

				// rs가 가리키는 레코드값을 VO에 넣는다.// rs가 가리키는 레코드값을 VO에 넣는다.
				vo.setNo(rs.getInt("no"));
				vo.setIdx(rs.getInt("idx"));
				vo.setName(rs.getString("name"));
				vo.setContent(rs.getString("content"));
				vo.setPwd(rs.getString("pwd"));
				vo.setIp(rs.getString("ip"));
				vo.setRegdate(rs.getString("regdate"));

			}

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (rs != null)
					rs.close();
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return vo;
	}// end:selectOne()

 

 

 

SQL 문에서 내용 수정문을 체크합니다.

 

 

 

넘길때 idx 값(수정할 데이터 값), no(내가 봤던 page로 넘어갈 수 있게) 값도 넘겨줘야 한다.

 

 

 

visit_modify_form에 idx와 no 값 넘겨주기

<body>
	<form>
		<!-- idx 값 넘겨주기(수정해야할 데이터 지정) -->
		<!-- vo에 대한 정보가 넘어왔기에 vo.idx / param.no 가능 -->
		<input type="hidden" name="idx" value="${ requestScope.vo.idx }">
		<input type="hidden" name="no" value="${ param.no }">

 

 

 

Vo에 생성자 추가

	public VisitVo(int idx, String name, String content, String pwd, String ip) {
		super();
		this.idx = idx;
		this.name = name;
		this.content = content;
		this.pwd = pwd;
		this.ip = ip;
	}

 

 

 

modify Servlet 만들어주기

package action;

import java.io.IOException;

import dao.VisitDao;
import db.vo.VisitVo;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class VisitModifyAction
 */
@WebServlet("/visit/modify.do")
public class VisitModifyAction extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 수신 인코딩 설정
		request.setCharacterEncoding("utf-8");
		
		// parameter 받기
		int idx = Integer.parseInt(request.getParameter("idx"));
		String no = request.getParameter("no");
		String name = request.getParameter("name");
		String content = request.getParameter("content").replaceAll("\n", "<br>");
		String pwd = request.getParameter("pwd");
		
		// ip주소 얻어온다
		String ip = request.getRemoteAddr();
		
		// VisitVo 포장
		VisitVo vo = new VisitVo(idx, name, content, pwd, ip);
		
		// DB 수정하기
		int res = VisitDao.getInstance().update(vo);
		
		// 목록보기로 이동
		response.sendRedirect("list.do#p_" + no);

	}

}

 

 

 

 

Dao update() 추가

	public int update(VisitVo vo) {
		// TODO Auto-generated method stub

		int res = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;

		String sql = "update visit set name =?, content =?, pwd =?, ip =?, regdate = sysdate where idx=? ";

		try {
			// 1. Connection 얻어오기
			conn = DBService.getInstance().getConnection();

			// 2. PreparedStatement
			pstmt = conn.prepareStatement(sql);

			// 3. pstmt parameter index 채우기
			pstmt.setString(1, vo.getName());
			pstmt.setString(2, vo.getContent());
			pstmt.setString(3, vo.getPwd());
			pstmt.setString(4, vo.getIp());
			pstmt.setInt(5, vo.getIdx());

			// 4. DB update
			res = pstmt.executeUpdate();

		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			// 예외 처리에서 무조건 실행되는 부분
			// 마무리 작업(열린역순으로 닫기)
			// 한 번에 잡아서 try catch 하기 : alt + shift + s
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return res;

	}// end:update()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형