🍁Todo List
1. 주제
- Todo List
2. 업무
- 할일 쓰기
- 할일 보기(목록)
- 할일 수정하기
- 할일 삭제하기
3. DB
- Todo (script.sql)
4. 화면(+페이지)
- 할일 보기(목록) 페이지 (webapp > list.jsp)
- 할일 쓰기 페이지 (webapp > add.jsp, addok.jsp)
- 할일 수정 페이지 (webapp > editok.jsp)
- 할일 삭제 페이지 (webapp > delok.jsp)
- 템플릿 역할 (webapp > template.jsp)
5. 리소스
- 조각 페이지 (webapp > inc > header.jsp, asset.jsp)
- jQuery (webapp > js > jquery-1.12.js)
6. WEB-INF
- lib > ojdb6.jar 복사
구현 페이지
할일 보기(목록) 페이지, 할일 쓰기 페이지를 구현해야 한다고 하자. 그런데 실제로는 프로그램 처리만 하고 눈에 보이지 않는 페이지도 존재한다.
업무용 페이지는 최상위 폴더인 webapp에 만들고, 조각 페이지는 별도로 관리하므로 webapp 밑에 inc 폴더를 만들고 관리한다.
기본적으로 개발자는 게시판을 스스로 만들 줄 알아야 한다.
🍁DB
script.sql
--할일 테이블
DROP TABLE tblTodo;
DROP SEQUENCE seqTodo;
CREATE TABLE tblTodo (
seq NUMBER(10) PRIMARY KEY, --번호(PK)
todo VARCHAR2(1000) NOT NULL, --할일
state CHAR(1) DEFAULT 'n' NOT NULL, --미완료(n), 완료(y)
regdate DATE DEFAULT SYSDATE NOT NULL --날짜
);
CREATE SEQUENCE seqTodo;
SELECT * FROM tblTodo;
INSERT INTO tblTodo (seq, todo, state, regdate) VALUES (seqTodo.nextVal, '할일입니다.', DEFAULT, DEFAULT);
SELECT * FROM tblTodo orderby seq DESC;
SELECT * FROM tblTodo ORDER BY state ASC, seq desc;
UPDATE tblTodo SET state = 'y' WHERE seq = 1;
DELETE FROM tblTodo WHERE seq = 1;
COMMIT;
🍁화면(+페이지)
list.jsp
1. DB 작업 > select > ResultSet
2. ResultSet > 화면 출력
<%@page import="com.test.todo.DBUtil"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.Statement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//1. DB 작업
//2. ResultSet
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
try {
conn = DBUtil.open();
String sql = "SELECT * FROM tblTodo ORDER BY state ASC, seq";
stat = conn.createStatement();
rs = stat.executeQuery(sql);
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
<style>
table td {
}
table td:nth-child(1) {
text-align: center;
width: 20px;
border-right: 0;
}
table td:nth-child(2) {
width: auto;
border-left: 0;
border-right: 0;
}
table td:nth-child(3) {
text-align: center;
width: 20px;
border-left: 0;
}
table td:nth-child(3) > div{
display: none;
}
table tr:hover td:nth-child(3) > div{
display: block;
cursor: pointer;
}
</style>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
<table>
<% while(rs.next()) { %>
<tr>
<td>
<input type="checkbox" onchange="editTodo(<%= rs.getString("seq") %>)"; <% if(rs.getString("state").equals("y")) { out.print("checked");} %>>
</td>
<td>
<% if(rs.getString("state").equals("n")) { %>
<div><%= rs.getString("todo") %></div>
<% } else { %>
<div style="text-decoration: line-through;"><%= rs.getString("todo") %></div>
<% } %>
</td>
<td><div onclick="delTodo(<%= rs.getString("seq")%>);">×</div></td>
</tr>
<% } %>
</table>
<div>
<button class="add" onclick="location.href='add.jsp';">등록하기</button>
</div>
<script>
function editTodo(seq) {
//어떤 할일을 눌렀는지 확인
//alert(seq);
//editok.jsp?seq=1
location.href = 'editok.jsp?seq=' + seq;
};
function delTodo(seq) {
if (confirm('delete?')) {
location.href = 'delok.jsp?seq=' + seq;
}
}
</script>
</body>
</html>
<%
try {
rs.close();
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
%>
HTML, CSS 작업을 끝내고 JavaScript 작업을 한다.
내용물이 크지 않으면 클라이언트 코드와 서버 코드를 동시에 작성해도 되지만, 정석은 클라이언트 코드를 먼저 작성하고 서버 코드를 작성하는 것이다.
close 작성 위치
<%
try {
rs.close();
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
%>
ResultSet을 사용해야 하기 때문에 HTML이 끝나고 나서 스크립틀릿을 만들어 종료를 해 주어야 한다.
checked 단어 찍기
<input type="checkbox" onchange="editTodo(<%= rs.getString("seq") %>)"; <% if(rs.getString("state").equals("y")) { out.print("checked");} %>>
태그 안쪽에 스크립틀릿을 만들어 체크가 완료된 경우에 checked 단어를 찍는다.
add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
<style>
</style>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
<form method="POST" action="addok.jsp">
<table class="vertical">
<tr>
<th>할일</th>
<td><input type="text" class="long" name="todo" required></td>
</tr>
</table>
<div>
<button class="back" type="button" onclick="location.href='list.jsp';">돌아가기</button>
<button class="add">등록하기</button>
</div>
</form>
</body>
</html>
전송버튼과 보내고 싶은 내용은 하나의 <form> 태그 안에 들어 있어야 한다.
todo를 작성한 뒤에 전송할 것이기 때문에 text에 todo라는 name을 붙여 todo가 전송될 수 있게 하고, required 속성으로 필수 입력을 받도록 한다.
addok.jsp
1. 데이터 가져오기
2. DB 연결 > Insert 작업
3. 피드백 > list.jsp 이동
<%@page import="com.test.todo.DBUtil"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//1. 데이터 가져오기
request.setCharacterEncoding("UTF-8"); //한글 깨짐 현상 해결
String todo = request.getParameter("todo");
//2. DB 접속
Connection conn = null;
PreparedStatement stat = null;
int result = 0;
try {
conn = DBUtil.open();
String sql = "INSERT INTO tblTodo (seq, todo, state, regdate) VALUES (seqTodo.nextVal, ?, DEFAULT, DEFAULT)";
stat = conn.prepareStatement(sql);
stat.setString(1, todo);
result = stat.executeUpdate();
stat.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
<%-- <div><%= result %></div> --%>
<% if (result == 1) { %>
<div class="message">할일을 등록했습니다.</div>
<div><a href="list.jsp">목록보기</a></div>
<% } else { %>
<div class="message">할일을 실패했습니다.</div>
<div><a href="add.jsp">돌아가기</a></div>
<% } %>
<script>
<% if (result == 1) { %>
//alert('할일 등록 성공');
//location.href = 'list.jsp';
<% } else { %>
//alert('할일 등록 실패');
//location.href = 'add.jsp';
<% } %>
</script>
</body>
</html>
매개변수가 있기 때문에 stat을 PreparedStatement로 선언해야 한다.
그리고 매개변수가 들어갈 부분을 '?'로 바꾸고, 반환값은 없으므로 executeUpdate를 호출한다.
피드백은 보통 바깥에서 하므로 result 변수를 try catch문 바깥에서 선언한다.
editok.jsp
1. 데이터 가져오기(seq)
2. DB 작업 > Update 작업
3. 피드백
<%@page import="java.sql.ResultSet"%>
<%@page import="com.test.todo.DBUtil"%>
<%@page import="java.sql.Connection"%>
<%@page import="java.sql.PreparedStatement"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//1. 데이터 가져오기(seq)
String seq = request.getParameter("seq");
//2. DB 작업
Connection conn = null;
PreparedStatement stat = null;
try {
conn = DBUtil.open();
String sql = "";
//state에 y가 들어있는지 n가 들어있는지 확인
sql = "SELECT state FROM tblTodo WHERE seq = ?";
stat = conn.prepareStatement(sql);
stat.setString(1, seq);
ResultSet rs = stat.executeQuery();
String state = "";
if (rs.next()) {
state = rs.getString("state");
}
//토글 버튼
//n 이면 y로 변경
//y 이면 n로 변경
if (state.equals("n")) {
state = "y";
} else {
state = "n";
}
sql = "UPDATE tblTodo SET state = ? WHERE seq = ?";
stat = conn.prepareStatement(sql);
stat.setString(1, state); //첫 번째 ?에 state 삽입
stat.setString(2, seq); //두 번째 ?에 seq 삽입
int result = stat.executeUpdate();
if (result == 1) {
response.sendRedirect("list.jsp");
} else {
out.println("<script>");
out.println("alert('실패');");
out.println("location.href = 'list.jsp';");
out.println("</script>");
}
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
</body>
</html>
할 일의 상태를 완료로 바꾸는 작업을 할 수 있다.
<HTML> 태그 밖에서 작업을 하면 안 되지만, 개발의 편의성 때문에 작업을 하게 되기도 한다.
delok.jsp
1. 데이터 가져오기(seq)
2. DB 작업 > Delete 작업
3. 피드백
<%@page import="com.test.todo.DBUtil"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//1. 데이터 가져오기(seq)
String seq = request.getParameter("seq");
//2. DB 작업
Connection conn = null;
PreparedStatement stat = null;
try {
conn = DBUtil.open();
String sql = "ELETE FROM tblTodo WHERE seq = ?";
stat = conn.prepareStatement(sql);
stat.setString(1, seq);
int result = stat.executeUpdate();
if (result == 1) {
response.sendRedirect("list.jsp");
} else {
out.println("<script>");
out.println("alert('실패');");
out.println("location.href = 'list.jsp';");
out.println("</script>");
}
} catch (Exception e) {
e.printStackTrace();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
</body>
</html>
template.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%@ include file="inc/asset.jsp" %>
<style>
</style>
</head>
<body class="narrow">
<%@ include file="inc/header.jsp" %>
<script>
</script>
</body>
</html>
🍁조각 페이지
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<h1>Todo <small>List</small></h1>
페이지를 만들 때에는 초기 설계가 중요하다.
DBUtil
package com.test.todo;
import java.sql.Connection;
import java.sql.DriverManager;
public class DBUtil {
private static Connection conn;
public static Connection open() {
String url = "jdbc:oracle:thin:@localhost:1521:xe";
String id = "hr";
String pw = "java1234";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, id, pw);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static Connection open(String server, String id, String pw) {
String url = "jdbc:oracle:thin:@" + server + ":1521:xe";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, id, pw);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}