todo-list.jsp페이지의 forEach문 아래의 삭제에 해당하는 a태그의 속성을 추가하여 사용자의 확인을 한 번 받은 후 TodoController서블릿의 deleteTodo메서드로 넘어감
-todo-list.jsp-
<c:forEach var="todo" items="${listTodo}">
<tr>
<td><c:out value="${todo.title}" /></td>
<td><c:out value="${todo.targetDate}" /></td>
<td><c:out value="${todo.status}" /></td>
<td>
<a href="<%=request.getContextPath()%>/todos?action=edit&id=<c:out value='${todo.id}'/>" class="btn btn-outline-info btn-sm">수정</a>
<a href="<%=request.getContextPath()%>/todos?action=delete&id=<c:out value='${todo.id}'/>" onclick="if(!confirm('정말로 삭제하시겠습니까?')) return false" class="btn btn-outline-danger btn-sm">삭제</a>
<!-- ㄴ자바스크립트가 먼저 동작하므로 confirm창에서 확인을 누르면 a태그의 주소로 값이 넘어가 메서드를 차례로 실행하게 된다. 취소를 누르면 false값을 받도록 작성하여 아무일도 없도록 함 -->
</td>
</tr>
</c:forEach>
위 사진처럼 확인 창이 뜨고 '확인'을 누르면 action속성에 값을 가지고 doGet메서드로 이동한다.
'취소'를 누를 경우 값이 false가 되도록 하였으므로 동작이 없다.
-TodoController서블릿 doGet메서드-
// 요청주소가 localhost:8090/TODO/new 이면 => "/new"가 action의 값이 된다(ContextPath의 주소 이후만 action에 넣는다는뜻)
String action = request.getParameter("action"); // 주소가 TODO/todos?=text일때 text의 값을 action에 저장
System.out.println(action);
switch(action) {
case "new":
showNewForm(request, response);
break;
case "post":
insertTodo(request, response);
break;
case "delete":
deleteTodo(request, response);
break;
case "edit": // 수정form을 보여줌
showEditForm(request, response);
break;
case "update":
updateTodo(request, response);
break;
case "list": // localhost:8090/TODO/todos/list
listTodo(request, response);
break;
default: // 요청 주소가 기본(/)이거나 잘못되었을 경우, action이 없을때 로그인 페이지로 이동. 로그아웃시에도 여기로 오게된다.
HttpSession session = request.getSession();
session.invalidate(); // session에 저장된 로그인 정보를 전체삭제
RequestDispatcher dispatcher = request.getRequestDispatcher("login/login.jsp");
dispatcher.forward(request, response);
break;
}// switch문 끝
여기서 delete에 해당하므로 같은 서블릿의 deleteTodo메서드로 이동
-TodoController서블릿 deleteTodo메서드-
private void deleteTodo(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 삭제기능은 js를 통해 한번 확인작업을 거치는데 자바스크립트가 먼저 동작하기때문에 confirm창에서 확인을 눌러야 여기까지넘어오게 된다
Long id = Long.parseLong(request.getParameter("id")); // id를 받음
todoDAO.deleteTodo(id);
response.sendRedirect("todos?action=list"); // 삭제 후 다시 todo-list.jsp페이지로 돌아감
}
받아온 id값을 이용해 deleteTodo메서드로 해당 id의 DB의 데이터 한 행을 삭제한다.
삭제 후 단순 페이지 이동으로 todo-list.jsp페이지로 돌아가 현재 DB에 저장된 할일을 다시 출력한다.
로그아웃버튼을 누르면 action=logout의 값이 TodoController서블릿 doGet메서드로 넘어가 default로 설정된 값이 동작하게 된다.(바로위의 doGet메서드 참고)
-TodoController서블릿 doGet메서드의 일부-
// 요청 주소가 기본(/)이거나 잘못되었을 경우, action이 없을때 로그인 페이지로 이동. 로그아웃시에도 여기로 오게된다.
default:
HttpSession session = request.getSession();
session.invalidate(); // session에 저장된 로그인 정보를 전체삭제
RequestDispatcher dispatcher = request.getRequestDispatcher("login/login.jsp");
dispatcher.forward(request, response);
break;
invalidate()는 세션에 저장된 모든 정보를 삭제할 수 있는 메서드로,
session.invalidate() 과정을 거치면 세션에 저장되어있던 로그인 정보가 모두 삭제된다.
세션이 삭제된 후 forward로 login.jsp로 페이지를 이동한다.
참고. 세션에서 key값을 삭제할때:
session.removeAttribute(String key)
로그아웃을 마치면 login.jsp페이지로 forward방식으로 이동하게 된다.
질문.이전 페이지에서 반드시 받아와야하는 값이 없으므로 sendRedirect로 단순이동만 해도 괜찮지 않을까?
자바스크립트를 이용해 true이면 '완료됨', false이면 '진행중'으로 표시하도록 수정.
-todo-list.jsp-
<tr>
<td><c:out value="${todo.title}" /></td>
<td><c:out value="${todo.targetDate}" /></td>
<td class="status"><c:out value="${todo.status}" /></td>
<td>
<a href="<%=request.getContextPath()%>/todos?action=edit&id=<c:out value='${todo.id}'/>" class="btn btn-outline-info btn-sm">수정</a>
<a href="<%=request.getContextPath()%>/todos?action=delete&id=<c:out value='${todo.id}'/>" onclick="if(!confirm('정말로 삭제하시겠습니까?')) return false" class="btn btn-outline-danger btn-sm">삭제</a>
<!-- ㄴ자바스크립트가 먼저 동작하므로 confirm창에서 확인을 누르면 a태그의 주소로 값이 넘어가 메서드를 차례로 실행하게 된다. 취소를 누르면 false값을 받도록 작성하여 아무일도 없도록 함 -->
</td>
</tr>
~~~ 생략 ~~~
<script src="<%=request.getContextPath()%>/js/todo.js"></script>
현재상태 항목인 3번째 td에 status클래스 부여.
맨 아래 script 링크에 todo.js링크 추가.
-todo.js-
const statuses = document.querySelectorAll('.status'); // status클래스들을 변수 status에 배열로 저장
statuses.forEach((td) => {
if (td.textContent == 'false') td.textContent = '진행중';
else td.textContent = '완료됨';
});
querySelectorAll로 status클래스를 가진 모든 항목을 변수 statuses에 배열로 저장.
forEach문을 통해 모든 값을 if문으로 검사해 text가 false이면 '진행중', true이면 '완료됨'으로 수정해줌.
=> 수정하면 현재상태가 진행중, 완료됨 중 하나의 문구를 출력한다.
파이차트 참고사이트 링크
진행중, 완료의 갯수에 따라 파이차트로 표기.
-todo-list.jsp-
<br />
<table class="table table-bordered">
~~~ 생략 ~~~
</table>
<div class="row mt-5">
<div class="col-4 mx-auto">
<canvas id="myChart"></canvas>
</div>
</div>
~~~ 생략 ~~~
<script src="<%=request.getContextPath()%>/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="<%=request.getContextPath()%>/js/todo.js"></script>
table태그가 끝나는 아래 div클래스 추가.
bootstrap.bundle.js파일 링크아래에 chart.js링크 추가.
-todo.js-
let 진행 = 0;
let 완료 = 0;
statuses.forEach((td) => {
if (td.textContent == 'false') {
진행++;
td.textContent = '진행중';
} else {
완료++;
td.textContent = '완료됨';
}
});
const data = {
labels: ['진행중', '완료됨'],
datasets: [
{
label: 'My First Dataset',
data: [진행, 완료],
backgroundColor: ['rgb(255, 99, 132)', 'rgb(54, 162, 235)'],
hoverOffset: 4,
},
],
};
const config = { type: 'pie', data: data, };
const myChart = new Chart(document.getElementById('myChart'), config);
todo.js파일에 코드를 추가, 수정.
forEach반복문을 통해 모든 .status들이 if-else문을 통해 true와 false를 판별할 때 각각 변수 '진행'과 '완료'에 1씩 더해 파이차트에 비율을 반영한다.
=> 결과화면.