DB commit 하지 않으면 데이터가 안넘어갑니다. 꼭 확인해주세요
JDBC를 활용해서 방명록을 작성해보겠습니다.
흐름도는 대략적으로 이렇습니다.
Data Binding(데이터 연결) request
왼쪽은 전부 User의 요청처리이다. (url로 요청을 하게 된다) ->
Servlet이 각각의 요청을 처리하는 객체로 받아준다.
환경설정 세팅
템플릿을 저장해보자
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()
'데이터베이스↗' 카테고리의 다른 글
xml openApi 이용하기 (0) | 2024.07.08 |
---|---|
xml로 데이터를 가져와서 parsing까지 하기 (0) | 2024.07.08 |
JDBC 데이터 가져오기 예제 (DataBase -> Java -> Servlet -> JSP) (0) | 2024.06.19 |
[오류해결]Server Tomcat v10.1 Server at localhost failed to start. (0) | 2024.06.19 |
善DataBase JDBC(웹사이트 데이터 가져오는 경로까지) (0) | 2024.06.19 |