Servlet&JSP

Step02_DB (예제 : 할일목록 todo 만들기, 꾸미기 전)

bono.html 2022. 8. 17. 12:52

 

[ 할일(todo) 에 관련된 기능을 완성해 보세요 ]

- 할일 등록 날짜는 수정 안해도 됩니다 (할일 내용만 수정되도록)
- 할일 등록 할때는 SYSDATE 로 등록을 하세요 (할일 내용만 입력 받아서 저장하면 됨)
- 할일 목록에 등록일도 출력이 되어야 합니다. (DATE type도 .getString() 메소드로 읽어올 수 있다.)

 

in oracle

 

drop table todo;

drop sequence todo_seq;

CREATE TABLE todo( num NUMBER PRIMARY KEY,
content VARCHAR2(30) NOT NULL, regdate DATE );

CREATE SEQUENCE todo_seq;

 

in eclipse


/todo/list.jsp
/todo/insertform.jsp
/todo/insert.jsp
/todo/delete.jsp
/todo/updateform.jsp
/todo/update.jsp

test.todo.dato.TodoDto
test.todo.dato.TodoDao

 

 

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa" crossorigin="anonymous"></script>
</head>
<body >
	<!-- bootstrap 네비바 -->
	<nav class="navbar bg-light navbar-expand-sm">
	  <div class="container">
	    <a class="navbar-brand" href="${pageContext.request.contextPath }/">
	      <img src="https://getbootstrap.com/docs/5.2/assets/brand/bootstrap-logo.svg" alt="" width="30" height="24" class="d-inline-block align-text-top">
	      Acorn
	    </a>
	    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
	      <span class="navbar-toggler-icon"></span>
	    </button>
	    <div class="collapse navbar-collapse" id="navbarNav">
	       <ul class="navbar-nav">
	          <li class="nav-item">
	             <a class="nav-link" href="${pageContext.request.contextPath }/member/list.jsp">회원목록</a>
	          </li>
	          <li class="nav-item">
	             <a class="nav-link" href="${pageContext.request.contextPath }/todo/list.jsp">할일목록</a>
	          </li>
	       </ul>
	    </div>
	  </div>
	</nav>
	<div class="container">
		<h1>인덱스 페이지 입니다.</h1>
		<%--
			절대경로를 표시할때 컨텍스트 경로가 필요하긴 하지만
			컨텍스트 경로는 나중에 실제로 프로젝트가 끝나고 배포되는 시점에 변경되거나 제거될 예정이다.
			따라서 코딩할때 컨텍스트 경로를 실제로 코딩해 놓으면 나중에 제거하거나 변경할때 어려움이 예상된다.
			해결책은 jsp 페이지에서 context 경로가 필요하면 아래의 EL(Expression Language)을 이용해서 출력하면 된다.
		 --%>
		<p>컨텍스트 경로(프로젝트명) : <strong>${pageContext.request.contextPath }</strong></p>
		<ul>
			<li><a href="member/list.jsp">회원목록보기</a></li>
			<li><a href="todo/list.jsp">할일목록보기</a></li>
		</ul>
	</div>
</body>
</html>

index.jsp

 

DbcpBean.java

package test.util;

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
/*
 *  [ Data Base Connection Pool Bean ]
 *  - 최초 Connection 이 필요한 시점에 미리 Connection 여러개를 얻어내서 Connection Pool 에
 *    넣어 놓고 필요할때 가져다 쓰고 다 쓴다음 반납하는 구조로 사용한다.
 *    
 *  - Connection Pool 에서 Connection 한개를 가져오는 방법
 *  
 *    Connection conn=new DbcpBean().getConn();
 *    
 *  - 다 사용한 다음 반납하는 방법
 *  
 *    conn.close(); // close() 메소드를 호출하면 자동으로 Pool 에 반납된다.
 */
public class DbcpBean {
   //필드
   private Connection conn;
   
   //생성자
   public DbcpBean() {
      try {
         Context initContext = new InitialContext();
         Context envContext  = (Context)initContext.lookup("java:/comp/env");
         DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
         //리턴되는 Connection 객체를 필드에 저장하기
         conn = ds.getConnection();
         System.out.println("Connection 얻어오기 성공!");
      }catch(Exception e) {
         e.printStackTrace();
      }
   }
   
   //메소드
   public Connection getConn() {
      return conn;
   }
}

 

TodoDto.java

package test.todo.dto;

public class TodoDto {
	private int num;
	private String content;
	private String regdate;
	
	public TodoDto() {}

	public TodoDto(int num, String content, String regdate) {
		super();
		this.num = num;
		this.content = content;
		this.regdate = regdate;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getRegdate() {
		return regdate;
	}

	public void setRegdate(String regdate) {
		this.regdate = regdate;
	}
	
	
}

 

TodoDao.java

package test.todo.dao;

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

import test.member.dto.MemberDto;
import test.todo.dto.TodoDto;
import test.util.DbcpBean;

public class TodoDao {
	private static TodoDao dao;
	
	private TodoDao() {}
	
	public static TodoDao getInstance() {
      //만일 static 필드가 null 이면(최초로 getInstance() 메소드가 호출된 것이라면)
      if(dao==null) {
         //MemberDao 객체를 생성해서 static 필드에 저장한다.
         dao=new TodoDao();
      }
      //static 필드에 저장된 MemberDao 객체의 참조값을 리턴해 준다. 
      return dao;
   }
	
	public boolean insert(TodoDto dto) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		int updatedRowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 sql 문
			String sql="INSERT INTO todo"
			   		+ " (num, content, regdate)"
			   		+ " VALUES(todo_seq.NEXTVAL, ?, SYSDATE)";
			pstmt = conn.prepareStatement(sql);
			//? 값을 바인딩 할게 있으면 바인딩하기
			pstmt.setString(1, dto.getContent());
			//insert, update, delete 를 수행하고 변화된 row 의 갯수를 리턴 받기
			updatedRowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e) {
			}
		}
		//변화된 row 의 갯수가 0 보다 크면 작업 성공
		if (updatedRowCount > 0) {
			return true;
		} else {//그렇지 않으면 작업 실패
			return false;
		}
	}
	
   public boolean delete(int num) {
	    Connection conn = null;
		PreparedStatement pstmt = null;
		int updatedRowCount = 0;
		try {
			conn = new DbcpBean().getConn();
			//실행할 sql 문
			String sql = "DELETE FROM todo"
					+ " WHERE num=?";
			pstmt = conn.prepareStatement(sql);
			//? 값을 바인딩 할게 있으면 바인딩하기
			pstmt.setInt(1, num);
			//insert, update, delete 를 수행하고 변화된 row 의 갯수를 리턴 받기
			updatedRowCount = pstmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (pstmt != null)
					pstmt.close();
				if (conn != null)
					conn.close();
			} catch (Exception e) {
			}
		}
		//변화된 row 의 갯수가 0 보다 크면 작업 성공
		if (updatedRowCount > 0) {
			return true;
		} else {//그렇지 않으면 작업 실패
			return false;
		}
   }
   
   public boolean update(TodoDto dto) {
      Connection conn = null;
      PreparedStatement pstmt = null;
      int updatedRowCount = 0;
      try {
         conn = new DbcpBean().getConn();
         //실행할 sql 문
         String sql = "UPDATE todo"
               + " SET content=?"
               + " WHERE num=?";
         pstmt = conn.prepareStatement(sql);
         //? 값을 바인딩 할게 있으면 바인딩하기
         pstmt.setString(1, dto.getContent());
         pstmt.setInt(2, dto.getNum());
         //insert, update, delete 를 수행하고 변화되 row 의 갯수를 리턴 받기
         updatedRowCount = pstmt.executeUpdate();
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            if (pstmt != null)
               pstmt.close();
            if (conn != null)
               conn.close();
         } catch (Exception e) {
         }
      }
      //변화된 row 의 갯수가 0 보다 크면 작업 성공
      if (updatedRowCount > 0) {
         return true;
      } else {//그렇지 않으면 작업 실패
         return false;
      }
   }
   
   public TodoDto getData(int num) {
	   	  TodoDto dto=null;
	      Connection conn = null;
	      PreparedStatement pstmt = null;
	      ResultSet rs = null;
	      try {
	         //Connection 객체의 참조값 얻어오기 (Connection Pool 에서 하나 가져오기)
	         conn = new DbcpBean().getConn();
	         //실행할 sql 문 작성
	         String sql = "SELECT content, TO_CHAR(regdate,'YYYY.MM.DD HH24:MI') regdate"
	               + " FROM todo"
	               + " WHERE num=?";
	         //sql 문을 전달하면서 PreparedStatement 객체의 참조값 얻어오기
	         pstmt = conn.prepareStatement(sql);
	         //? 에 값을 바인딩 할게 있으면 한다.
	         pstmt.setInt(1, num);
	         //select 문 수행하고 결과를 ResultSet 으로 받아온다.
	         rs = pstmt.executeQuery();
	         //반복문 돌면서 ResultSet 의 cursor 를 한칸씩 내린다.
	         while (rs.next()) {
	            //cursor 가 위치한 곳의 칼럼 데이터 추출해서 어딘가에 담기 
	            dto=new TodoDto();
	            dto.setNum(num);
	            dto.setContent(rs.getString("content"));
	            dto.setRegdate(rs.getString("regdate"));
	         }

	      } catch (Exception e) {
	         //혹시 예외가 발생한다면 예외정보를 콘솔에 출력해서 에러의 원인 찾기 
	         e.printStackTrace();
	      } finally {
	         try {
	            if (rs != null)
	               rs.close();
	            if (pstmt != null)
	               pstmt.close();
	            if (conn != null)
	               conn.close(); //Connection 반납
	         } catch (Exception e) {
	         }
	      }
	      return dto;
	   }

	//전체 회원의 목록을 리턴하는 메소드 
	public List<TodoDto> getList(){
		  
		  //회원 목록을 담을 객체 생성
		  List<TodoDto> list=new ArrayList<>();
		   
	   Connection conn=null;
	   PreparedStatement pstmt=null;
	   ResultSet rs=null;
	   try {
	 	  //Connection 객체의 참조값 얻어오기 (Connection Pool 에서 하나 가져오기)
	 	  conn=new DbcpBean().getConn();
	 	  //실행할 sql 문 작성
	 	  String sql="SELECT num, content, TO_CHAR(regdate,'YYYY.MM.DD HH24:MI') regdate"
	 	  		+ " FROM todo"
	 	  		+ " ORDER BY num ASC";
	 	  //sql 문을 전달하면서 PreparedStatement 객체의 참조값 얻어오기
	 	  pstmt=conn.prepareStatement(sql);
	 	  //?에 값을 바인딩 할게 있으면 한다.
	 	  
	 	  //select 문 수행하고 결과를 ResultSet으로 받아온다.
	 	  rs=pstmt.executeQuery();
	 	  //반복문 돌면서 ResultSet의 cursor 를 한칸씩 내린다.
	 	  while(rs.next()) {
	 		  //cursor가 위치한 곳의 칼럼 데이터 추출해서 어딘가에 담기
	 		  
	 		  //TodoDto 객체를 생성해서
	 		  TodoDto dto=new TodoDto();
	 		  //ResultSet 에서 읽어온 정보를 MemberDto 객체의 setter 메소드를 이용해서 담는다.
	 		  dto.setNum(rs.getInt("num"));
	 		  dto.setContent(rs.getString("content"));
	 		  dto.setRegdate(rs.getString("regdate"));
	 		  //회원 한명의 정보를 담고 있는 MemberDto 객체의 참조값을 ArrayList 객체에 누적 시키기
	 		  list.add(dto);
	 	  }
	   }catch(Exception e) {
	 	  //혹시 예외가 발생한다면 예외정보를 콘솔에 출력해서 에러의 원인 찾기
	 	  e.printStackTrace();
	   }finally {
	 	  try {
	 		  if(rs!=null)rs.close();
	 		  if(pstmt!=null)pstmt.close();
	 		  if(conn!=null)conn.close(); //Connection 반납
	 	  }catch(Exception e) {}
	   }
	   //ArrayList 객체의 참조값 리턴하기
	   return list;
	}
}

 

list.jsp

<%@page import="test.todo.dto.TodoDto"%>
<%@page import="java.util.List"%>
<%@page import="test.todo.dao.TodoDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//MemberDao 객체의 참조값을 얻어와서
	TodoDao dao=TodoDao.getInstance();
	//회원목록을 얻어온다.
	List<TodoDto> list=dao.getList();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/todo/list.jsp</title>
<style>
#customers {
  font-family: Arial, Helvetica, sans-serif;
  border-collapse: collapse;
  width: 100%;
}

#customers td, #customers th {
  border: 1px solid #ddd;
  padding: 8px;
}

#customers tr:nth-child(even){background-color: #f2f2f2;}

#customers tr:hover {background-color: #ddd;}

#customers th {
  padding-top: 12px;
  padding-bottom: 12px;
  text-align: left;
  background-color: #04AA6D;
  color: white;
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
</head>
<body class="container">
	<h1 style="margin:20px; font-size:20px; text-align:center;">할일 목록</h1>
	<table id="customers">
		<thead>
			<tr>
				<th>번호</th>
				<th>할일</th>
				<th>날짜</th>
				<th>수정</th>
				<th>삭제</th>
			</tr>
		</thead>
		<tbody>
		<%for(TodoDto tmp:list) {%>
			<tr>
				<td><%=tmp.getNum() %></td>
				<td><%=tmp.getContent() %></td>
				<td><%=tmp.getRegdate() %></td>
				<td>
					<a href="updateform.jsp?num=<%=tmp.getNum() %>">수정</a>
				</td>
				<td>
					<a href="delete.jsp?num=<%=tmp.getNum() %>">삭제</a>
				</td>
			</tr>
		<%} %>
		</tbody>
	</table>
	<br>
	<form action="insertform.jsp" method="post">
		<button type="submit" class="btn btn-outline-success">할일 추가</button>
	</form>
</body>
</html>

list.jsp

 

insertform.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>insertform.jsp</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
</head>
<body>
<div class="container">
	<h1 style="margin:20px; font-size:20px; text-align:center;">할일 추가 폼 입니다.</h1>
	<form action="insert.jsp" method="post">
		<div>
			<label for="content"  class="form-label">할일</label>
			<input type="text" name="content" class="form-control" id="content" />
		</div>
		<br>
		<button type="submit" class="btn btn-outline-success">추가</button>
	</form>
</div>
</body>
</html>

insertform.jsp

 

insert.jsp

<%@page import="test.todo.dao.TodoDao"%>
<%@page import="test.todo.dto.TodoDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
   //post 방식 전송 파라미터 추출할때 한글깨지지 않도록
   request.setCharacterEncoding("utf-8");

   //1. 폼 전송되는 title을 추출한다
   String content=request.getParameter("content");
   
   //MemberDto 객체에 회원 정보를 담고
   TodoDto dto=new TodoDto();
   dto.setContent(content);

   //2. DB 에 저장한다.
   TodoDao dao=TodoDao.getInstance();
   //MemberDao 객체를 이용해서 DB 에 저장을 하고 성공여부를 리턴 받는다.
   boolean isSuccess=dao.insert(dto);
   //3. 응답한다.
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/todo/insert.jsp</title>
</head>
<body>
	<div class="container">
		<h1>알림</h1>
		<%if(isSuccess){ %>
			<p>
				<strong><%=content %></strong>의 정보를 추가 했습니다.
				<a href="list.jsp">확인</a>
			</p>
		<%}else{ %>
			<p>
				회원정보 추가 실패!
				<a href="insertform.jsp">다시 입력</a>
			</p>
		<%} %>
	</div>
</body>
</html>

insert.jsp

 

delete.jsp

<%@page import="test.todo.dao.TodoDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//1. get 방식 파라미터로 전달되는 삭제할 회원의 번호를 읽어온다.
	int num=Integer.parseInt(request.getParameter("num"));
	//2. DB 에서 해당 회원의 정보를 삭제한다
	boolean isSuccess=TodoDao.getInstance().delete(num);
	//3. 응답한다.
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/todo/delete.jsp</title>
</head>
<body>
	<%if (isSuccess){%>
		<script>
			alert("삭제 했습니다.");
			location.href="list.jsp";
		</script>
	<%}else{ %>
		<script>
			alert("삭제 실패!");
			location.href="list.jsp";	
		</script>
	<%} %>
</body>
</html>

delete.jsp

 

updateform.jsp

<%@page import="test.todo.dto.TodoDto"%>
<%@page import="test.todo.dao.TodoDao"%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//1. get 방식 파라미터로 전달되는 수정할 회원의 번호를 읽어온다.
	int num=Integer.parseInt(request.getParameter("num"));
	//2. DB에서 수정할 회원의 정보를 얻어온다.
	TodoDto dto=TodoDao.getInstance().getData(num);
	//3. 수정할 회원의 정보를 form 에 출력해서 응답한다.
%>
<!DOCTYPE html>
<html>
<head>
<style>
	label{margin-top:8px;}
</style>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
<title>/todo/updateform.jsp</title>
</head>
<body>
	<div class="container">
		<h1 style="margin:20px; font-size:20px; text-align:center;">회원 정보 수정 폼</h1>
		<form action="update.jsp" method="post">
			<!-- input type="hidden" 은 화면상에 보이지는 않지만 폼을 전송하면 같이 전송된다 -->
			<input type="hidden" name="num" value="<%=dto.getNum()%>"/>
			<input type="hidden" name="regdate" value="<%=dto.getRegdate()%>"/>
			<div>
				<label for="num" class="form-label">번호</label>
				<input type="text" class="form-control" id="num" value="<%=dto.getNum()%>" disabled/>
			</div>
			<div>
				<label for="regdate" class="form-label">날짜</label>
				<input type="text" class="form-control" id="regdate" value="<%=dto.getRegdate()%>" disabled/>
			</div>
			
			<div>
				<label for="content" class="form-label">할일</label>
				<input type="text" name="content" class="form-control" id="content" value="<%=dto.getContent()%>"/>
			</div>
			<br>
			<button type="submit" class="btn btn-outline-success">수정확인</button>
			<button type="reset" class="btn btn-outline-success">수정취소</button>
		</form>
	</div>
</body>
</html>

updateform.jsp

 

update.jsp

<%@page import="test.todo.dto.TodoDto"%>
<%@page import="test.todo.dao.TodoDao"%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
   request.setCharacterEncoding("utf-8");

   //1. 폼 전송되는 수정할 회원의 정보를 읽어온다.
   int num=Integer.parseInt(request.getParameter("num"));
   String content=request.getParameter("content");
   String regdate=request.getParameter("regdate");

   TodoDto dto=new TodoDto(num, content, regdate);
   //2. DB 에 수정 반영한다.
   boolean isSuccess=TodoDao.getInstance().update(dto);
   //3. 응답한다.
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/todo/update.jsp</title>
</head>
<body>
   <div class="container">
      <h1>알림</h1>
      <%if(isSuccess){ %>
         <p>
            <strong><%=num %></strong> 번째 할일 정보를 수정 했습니다.
            <a href="list.jsp">확인</a> 
         </p>
      <%}else{ %>
         <p>
            수정 실패! <a href="updateform.jsp?num=<%=num%>">다시 시도</a>
         </p>
      <%} %>
   </div>   
</body>
</html>

update.jsp