TodoController
package com.tenco.controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import com.tenco.model.TodoDAO;
import com.tenco.model.TodoDAOImpl;
import com.tenco.model.TodoDTO;
import com.tenco.model.UserDTO;
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 jakarta.servlet.http.HttpSession;
//.../mvc/todo/xxx
@WebServlet("/todo/*")
public class TodoController extends HttpServlet {
private static final long serialVersionUID = 1L;
private TodoDAO todoDAO;
public TodoController() {
todoDAO = new TodoDAOImpl(); // 업 캐스팅 된 상태
}
// http://localhost:8080/mvc/todo/form
// http://localhost:8080/mvc/todo/todoform (권장 x) (지금은 이거 사용)
// ex) http://localhost:8080/mvc/todo/formzzz
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 로그인 한 사용자만 접근을 허용하도록 설계
HttpSession session = request.getSession();
UserDTO principal = (UserDTO)session.getAttribute("principal"); // 다운캐스팅
// 인증검사
if(principal == null) {
// 로그인을 안한 상태
response.sendRedirect("/mvc/user/signIn?message=invalid");
return;
}
String action = request.getPathInfo();
System.out.println("action 확인 : " +action);
switch(action) {
case "/todoForm":
todoFormPage(request, response); // ctr + 1 번 클릭 후 메서드 생성
break;
case "/list":
System.out.println("응답 이후 확인 ~~~~~");
todoListPage(request, response, principal.getId()); // ctr + 1 번 클릭 후 메서드 생성
break;
case "/detail":
todoDetailPage(request, response, principal.getId() ); // ctr + 1 번 클릭 후 메서드 생성
// alt + shift + r : 이름수정
break;
case "/delete":
// TODO 수정 예정 1번에 principalId 넣기
deleteTodo(request, response, principal.getId()); // ctr + 1 번 클릭 후 메서드 생성
break;
default:
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404를 출력
break;
}
}
/**
* todo 삭제 기능
* @param request
* @param response
* @param principalId
* @throws IOException
*/
private void deleteTodo(HttpServletRequest request, HttpServletResponse response, int principalId) throws IOException {
System.out.println("222222222222222222222 : " + request.getParameter("id"));
try {
int todoId = Integer.parseInt(request.getParameter("id"));
todoDAO.deleteTodo(todoId, principalId);
} catch (Exception e) {
System.out.println("xxxxxxxxxxxx");
e.printStackTrace();
//response.sendRedirect(request.getContextPath() + "/todo/list?error=invalid");
}
System.out.println("yyyyyyyyyyyyyyy");
response.sendRedirect(request.getContextPath() + "/todo/list");
}
// 상세보기 화면
/**
*
* @param request
* @param response
* @throws IOException
*/
private void todoDetailPage(HttpServletRequest request, HttpServletResponse response, int principalId) throws IOException {
// detail?id=8;
try {
// todo - pk - 1, 3, 5 (야스오)
// todo - pk - 2, 4, 6 (홍길동)
int todoId = Integer.parseInt(request.getParameter("id"));
TodoDTO dto = todoDAO.getTodoById(todoId);
if(dto.getUserId() == principalId) {
// 상세보기 화면으로 이동
request.setAttribute("todo", dto);
request.getRequestDispatcher("/WEB-INF/views/todoDetail.jsp").forward(request, response);
} else {
// 권한이 없습니다 or 잘못된 접근입니다.
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("<script> alert('권한이 없습니다.'); history.back(); </script>");
// history.back(); 뒤로 돌아가기
}
// dto(userId)
} catch (Exception e) {
response.sendRedirect(request.getContextPath() + "/todo/list?error=invaild");
}
}
// http://localhost:8080/mvc/todo/list
/**
* 사용자별 todo 리스트 화면 이동
* @param request
* @param response
* @param principalId
* @throws IOException
* @throws ServletException
*/
private void todoListPage(HttpServletRequest request, HttpServletResponse response, int principalId) throws IOException, ServletException {
// request.getPathInfo() --> URL 요청에 있어 데이터 추출
// request.getParameter() --> URL 요청에 있어 데이터 추출
// request.getAttribute() --> 뷰를 내릴 속성에 값을 담아서 뷰로 내릴 때 사용
List<TodoDTO> list = todoDAO.getTodosByUserId(principalId);
request.setAttribute("list", list);
System.out.println("99999999999999999");
// todoList.jsp 페이지로 내부에서 이동 처리
request.getRequestDispatcher("/WEB-INF/views/todoList.jsp").forward(request, response);
}
/*
* todo 작성 페이지 이동
* @param
*/
// http://localhost:8080/mvc/user/signIn
private void todoFormPage(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.getRequestDispatcher("/WEB-INF/views/todoForm.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// todo 추가 예정
HttpSession session = request.getSession(); // 사용자가 로그인 했는지 안했는지 확인
UserDTO principal = (UserDTO)session.getAttribute("principal");
if(principal == null) {
response.sendRedirect(request.getContextPath() + "/user/siginIn?error=invaild");
return;
}
String action = request.getPathInfo();
System.out.println("action 확인 : " +action);
switch(action) {
case "/add":
// TODO 수정 예정 1번에 principalId 넣기
addTodo(request, response, principal.getId()); // ctr + 1 번 클릭 후 메서드 생성
break;
case "/update":
// TODO 수정 예정 1번에 principalId 넣기
updateTodo(request, response, principal.getId()); // ctr + 1 번 클릭 후 메서드 생성
break;
default:
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404를 출력
break;
}
}
/**
* todo 수정 기능
* @param request
* @param response
* @param principalId - 세션 ID 값
* @throws IOException
*/
private void updateTodo(HttpServletRequest request, HttpServletResponse response, int principalId) throws IOException {
try {
int todoId = Integer.parseInt(request.getParameter("id"));
// System.out.println("todoId : " + todoId);
String title = request.getParameter("title");
String description = request.getParameter("description");
String dueDate = request.getParameter("dueDate");
// CheckBox는 여러개 선택 가능한 태그 : String[] 배열로 선언 했음
// 이번에 CheckBox 는 하나만 사용 중
// 체크박스가 선택되지 않았으면 NULL 을 반환하고 체크가 되어있다면 "on" 문자열로 넘어온다.
System.out.println("3333333 : "+request.getParameter("completed"));
boolean completed = "on".equalsIgnoreCase(request.getParameter("completed"));
System.out.println("completed : " + completed);
// on 문자열이 대문자인지 소문자인지 상관없이 받아서 true false 확인
// System.out.println("completed : " +completed);
TodoDTO dto = TodoDTO.builder()
.id(todoId)
.userId(principalId)
.title(title)
.description(description)
.dueDate(dueDate)
.completed(String.valueOf(completed))
.build();
todoDAO.updateTodo(dto, principalId);
} catch (Exception e) {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println("<script> alert('잘못된 요청입니다.'); history.back(); </script>");
}
// list 화면 재 요청 처리
response.sendRedirect(request.getContextPath() +"/todo/list");
}
/*
* 세션별 사용자 ToDo 등록
* @param request
* @param response
* @param principalId : 세션에 담겨 있는 UserId 값
*/
private void addTodo(HttpServletRequest request, HttpServletResponse response, int principalId) throws IOException {
String title = request.getParameter("title");
String description = request.getParameter("description");
String dueDate = request.getParameter("dueDate");
// CheckBox는 여러개 선택 가능한 태그 : String[] 배열로 선언 했음
// 이번에 CheckBox 는 하나만 사용 중
// 체크박스가 선택되지 않았으면 NULL 을 반환하고 체크가 되어있다면 "on" 문자열로 넘어온다.
boolean completed = "on".equalsIgnoreCase(request.getParameter("completed"));
// on 문자열이 대문자인지 소문자인지 상관없이 받아서 true false 확인
// System.out.println("completed : " +completed);
TodoDTO dto = TodoDTO.builder()
.userId(principalId)
.title(title)
.description(description)
.dueDate(dueDate)
.completed(String.valueOf(completed))
.build();
todoDAO.addTodo(dto, principalId);
response.sendRedirect(request.getContextPath() + "/todo/list");
}
}
todoList.jsp
<%@page import="java.util.Date"%>
<%@page import="com.tenco.model.TodoDTO"%>
<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@ 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" type="text/css" href="../css/style.css">
</head>
<body>
<!-- http://localhost:8080/mvc/todo/todoList.jsp -->
<!-- http://localhost:8080/mvc/user/signIn <-- 여기서 부터 시작 -->
<!-- http://localhost:8080/mvc/todo/list -->
<%
List<TodoDTO> todoList = (List<TodoDTO>)request.getAttribute("list");
// out.print("todoList " + todoList);
// out.print(todoList.toString());
if (todoList != null && !todoList.isEmpty()) {
%>
<h2>할 일 목록</h2>
<a href="todoForm"> 새 할일 추가 </a>
<table border="1">
<tr>
<th>제목</th>
<th>설명</th>
<th>마감일</th>
<th>완료여부</th>
<th>(액션-버튼)</th>
</tr>
<%
for (TodoDTO todo : todoList) {
%>
<tr>
<td><%=todo.getTitle()%></td>
<td><%=todo.getDescription()%></td>
<td><%=todo.getDueDate()%></td>
<td><%=todo.completedToString() == "true" ? "완료" : "미완료"%></td>
<td><a href="detail?id=<%=todo.getId()%>">상세보기</a> <!-- 삭제 기능 -->
<form action="delete" method="get">
<input type="hidden" name="id" value="<%=todo.getId()%>">
<button type="submit">삭제</button>
</form></td>
</tr>
<%
}
%>
</table>
<%
} else {
%>
<hr>
<p>등록된 할 일이 없습니다.</p>
<%
}
%>
</body>
</html>
TodoDAO
package com.tenco.model;
import java.util.List;
public interface TodoDAO {
// 저장 기능
void addTodo(TodoDTO dto, int principalId);
TodoDTO getTodoById(int id);
// 사용자 아이디 기준으로 출력 todoList를 뽑는다.
List<TodoDTO> getTodosByUserId(int userId);
// 전체 리스트 출력
List<TodoDTO> getALLTodos();
// 사용자 글 업데이트
void updateTodo(TodoDTO dto, int principalId);
// 사용자 글 삭제
void deleteTodo(int id, int principalId);
}
TodoDAOImpl
package com.tenco.model;
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.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class TodoDAOImpl implements TodoDAO {
private DataSource dataSource;
public TodoDAOImpl() {
InitialContext ctx;
try {
ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:comp/env/jdbc/MyDB");
} catch (NamingException e) {
e.printStackTrace();
}
}
@Override
public void addTodo(TodoDTO dto, int principalId) {
// sql 작업할 때
String sql = " insert into todos(user_id, title, description, due_date, completed)" + "values(?, ?, ?, ?, ?) ";
try (Connection conn = dataSource.getConnection()) {
conn.setAutoCommit(false); // 자동 커밋 x 내가 직접 커밋한다.
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, principalId);
pstmt.setString(2, dto.getTitle());
pstmt.setString(3, dto.getDescription());
pstmt.setString(4, dto.getDueDate()); // TodoDTO의 util을 sql로 변경
// if(dto.getCompleted() == "true") {}
pstmt.setInt(5, dto.getCompleted() == "true" ? 1 : 0);
pstmt.executeUpdate();
conn.commit(); // 커밋
} catch (Exception e) {
e.printStackTrace();
conn.rollback();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public TodoDTO getTodoById(int id) {
String sql = " SELECT * FROM todos WHERE id = ? ";
TodoDTO dto = null;
try (Connection conn = dataSource.getConnection();) {
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, id);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
dto = new TodoDTO();
dto.setId(rs.getInt("id"));
dto.setUserId(rs.getInt("user_id"));
dto.setTitle(rs.getString("title"));
dto.setDescription(rs.getString("description"));
dto.setDueDate(rs.getString("due_date"));
dto.setCompleted(rs.getString("Completed"));
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return dto;
} // end of getTodoById()
// ------------------------------------------------
@Override
public List<TodoDTO> getTodosByUserId(int userId) {
String sql = " SELECT * FROM todos WHERE user_id = ? ";
List<TodoDTO> todos = new ArrayList<TodoDTO>();
try {
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, userId);
try (ResultSet rs = pstmt.executeQuery();) {
while (rs.next()) {
TodoDTO dto = new TodoDTO(); // 메모리에 객체가 올라가야 사용할 수 있다.
dto.setId(rs.getInt("id")); // db의 속성에 맞게 적어야 한다.
dto.setUserId(rs.getInt("user_id"));
dto.setTitle(rs.getString("title"));
dto.setDescription(rs.getString("description"));
dto.setDueDate(rs.getString("due_date"));
dto.setCompleted(rs.getString("completed"));
todos.add(dto);
}
} catch (Exception e) {
// TODO: handle exception
}
} catch (SQLException e) {
e.printStackTrace();
}
return todos;
} // end of getTodosByUserId()
@Override
public List<TodoDTO> getALLTodos() {
// List는 인터페이스 이다.
// List는 자신에게 맞는 구현클래스를 사용할수 있기에 ex) arrayList나 다른 리스트 등을 쓴다.
String sql = " SELECT * FROM todos ";
List<TodoDTO> todos = new ArrayList<TodoDTO>();
try {
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
try (ResultSet rs = pstmt.executeQuery();) {
while (rs.next()) {
TodoDTO dto = new TodoDTO(); // 메모리에 객체가 올라가야 사용할 수 있다.
dto.setId(rs.getInt("id")); // db의 속성에 맞게 적어야 한다.
dto.setUserId(rs.getInt("user_id"));
dto.setTitle(rs.getString("title"));
dto.setDescription(rs.getString("description"));
dto.setDueDate(rs.getString("due_date"));
dto.setCompleted(rs.getString("completed"));
todos.add(dto);
}
} catch (Exception e) {
// TODO: handle exception
}
} catch (SQLException e) {
e.printStackTrace();
}
return todos;
} // end of getALLTodos()
@Override
public void updateTodo(TodoDTO dto, int principalId) {
// SELECT <-- 있지 없지 확인 과정 (필요)
String sql = " UPDATE todos SET title = ?, description = ? " + " , due_date = ?, completed = ? "
+ " WHERE id = ? and user_id = ? ";
try (Connection conn = dataSource.getConnection()) {
conn.setAutoCommit(false);
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, dto.getTitle());
pstmt.setString(2, dto.getDescription());
pstmt.setString(3, dto.getDueDate());
pstmt.setInt(4, dto.getCompleted() == "true" ? 1 : 0);
pstmt.setInt(5, dto.getId());
pstmt.setInt(6, dto.getUserId());
pstmt.executeUpdate();
conn.commit();
} catch (Exception e) {
conn.rollback();
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} // end of updateTodo()
@Override
public void deleteTodo(int id, int principalId) {
String sql = "delete from todos where id = ? and user_id = ? ";
try (Connection conn = dataSource.getConnection();) {
conn.setAutoCommit(false);
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
pstmt.setInt(2, principalId);
pstmt.executeUpdate();
conn.commit();
} catch (Exception e) {
conn.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
}
} // end of deleteTodo()
}
todoDetail.jsp
<%@page import="com.tenco.model.TodoDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세보기 화면</title>
</head>
<body>
<h2>상세 보기</h2>
<%
TodoDTO todo = (TodoDTO)request.getAttribute("todo");
if(todo != null) {
%>
<p>제목 : <%=todo.getTitle() %></p><br>
<p>설명 : <%=todo.getDescription() %></p><br>
<p>마감일 : <%=todo.getDueDate() %></p><br>
<p>완료여부 : <%=todo.completedToString() == "true" ? "완료" : "미완료" %></p><br>
<hr><br>
<form action="update" method="post">
<input type="hidden" name="id" value="<%=todo.getId()%>">
<label for="title">제목 : </label>
<input type="text" id="title" name="title" value="<%=todo.getTitle()%>">
<br>
<label for="description">설명 : </label>
<input type="text" id="description" name="description" value="<%=todo.getDescription()%>">
<br>
<label for="dueDate">마감일 : </label>
<input type="date" id="dueDate" name="dueDate" value="<%=todo.getDueDate()%>">
<br>
<label for="completed">완료여부 : </label>
<input type="checkbox" id="completed" name="completed" <%= todo.completedToString() == "true" ? "checked" : ""%> >
<br>
<button type="submit">수정</button>
</form>
<%
} else {
out.print("<p> 정보를 불러오는데 실패 </p>");
}
%>
</body>
</html>