다음은 호두스케쥴러의 메인 기능인 '일정' 메뉴이다. 흔히 알고 있는 To do list를 작성하고 관리할 수 있는 페이지이다.

input창에 일정을 입력하여 저장 버튼을 누르면 DB에 저장이 되고 화면의 이동 없이 내가 저장했던 todolist가 비동기적으로 보여지도록 ajax를 사용했다.
또한 일정 완료/되돌리기/삭제 버튼을 누를 때에도 DB 수정과 동시에 화면 이동없이 taskList 부분만 비동기적으로 다시 렌더링되도록 ajax를 사용했다.
소스코드는 아래와 같다.
<%@ 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>
</head>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$.ajax({
url : "taskList",
type : "get",
success : function(result) {
$("#taskArea").html(result);
},
error : function() {
alert("일정 불러오기 실패!");
}
})
})
</script>
<body>
<jsp:include page="../common/menubar.jsp"></jsp:include>
<h2 class="mt-5 container" style="text-align: center;">
<label>To Do List</label>
</h2>
<div class="container mt-5">
<form class="row g-3" action="insert" method="post">
<div class="col-3" style="text-align: right;">
<label for="staticEmail2" class="col-form-label">오늘의 할일</label>
</div>
<div class="col-6">
<input type="text" class="form-control" name="content"
placeholder="할일을 입력하세요.">
</div>
<div class="col-3">
<button id="submitBtn" class="btn btn-primary mb-3">저장</button>
</div>
</form>
</div>
<div id="taskArea">
<jsp:include page="../task/taskList.jsp"></jsp:include>
</div>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<div class="container mt-5 col-8" id="task">
<c:forEach items="${list}" var="one">
<%-- <input name="taskId" type="hidden" value="${one.taskId}"> --%>
<div id="${one.taskId}" class=" mb-1" style="display: flex;">
<c:choose>
<c:when test="${one.complete == 'N'}">
<input class="form-control " type="text" value="${one.content}"
readonly style="margin-right: 5px;">
<div class="col-auto">
<button name="${one.taskId}" class="btn btn-primary"
style="margin-right: 5px; background-color: green;">완료</button>
</c:when>
<c:otherwise>
<input class="form-control " type="text" value="${one.content}"
readonly style="margin-right: 5px; background-color: lightgray;">
<div class="col-auto">
<button name="${one.taskId}" class="btn btn-primary"
style="margin-right: 5px; background-color: gray;">취소</button>
</c:otherwise>
</c:choose>
</div>
<div class="col-auto">
<button name="${one.taskId}" class="btn btn-primary"
style="background-color: red;">삭제</button>
</div>
</div>
</c:forEach>
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
<script type="text/javascript">
$(function() {
$("button").click(function() {
let btn = $(this).text();
let taskId = $(this).attr("name");
console.log(taskId);
console.log(btn);
if (btn == "완료" || btn == "취소") {
$.ajax({
url : "taskComplete",
type : "post",
contentType : 'application/json',
data : JSON.stringify({
btn : btn,
taskId : taskId
}),
success : function(result) {
$("#taskArea").html(result);
},
error : function() {
alert("일정 불러오기 실패!");
}
})
} else if (btn == "삭제") {
$.ajax({
url : "taskDelete",
type : "post",
contentType : 'application/json',
data : JSON.stringify({
btn : btn,
taskId : taskId
}),
success : function(result) {
$("#taskArea").html(result);
},
error : function() {
alert("일정 불러오기 실패!");
}
})
}
})
})
</script>
@SessionAttributes("loginUser")
@Controller
@RequestMapping("/task")
public class TaskController {
private TaskService taskService;
@Autowired
public TaskController(TaskService taskService) {
super();
this.taskService = taskService;
}
@RequestMapping("/list")
public String taskMain(HttpSession session) {
if (session.getAttribute("loginUser") == null) {
return "common/loginRedirectPage";
} else {
return "task/taskMain";
}
}
@PostMapping("/insert")
public String insertTask(TaskDTO taskDTO, HttpSession session, Model model) {
UserDTO loginUser = (UserDTO) session.getAttribute("loginUser");
taskDTO.setUserId(loginUser.getUserId());
taskDTO.setTaskId(UUID.randomUUID().toString());
String page = "";
try {
int result = taskService.insertTask(taskDTO);
if (result > 0) {
page = "redirect:/task/list";
} else {
model.addAttribute("msg", "할일 저장 실패");
page = "redirect:/task/list";
}
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("msg", "할일 저장 실패");
page = "redirect:/task/list";
}
return page;
}
@RequestMapping("/taskList")
public void selectTaskList(HttpSession session, Model model) {
UserDTO loginUser = (UserDTO) session.getAttribute("loginUser");
try {
ArrayList<TaskDTO> list = taskService.selectTaskList(loginUser);
model.addAttribute("list", list);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@PostMapping("/taskComplete")
public String updateTask(@RequestBody Map<String, String> data, Model model, HttpSession session) {
UserDTO loginUser = (UserDTO) session.getAttribute("loginUser");
TaskDTO taskDTO = new TaskDTO();
String complete = data.get("btn").equals("완료") ? "Y" : "N";
String page = "";
taskDTO.setComplete(complete);
taskDTO.setTaskId(data.get("taskId"));
try {
ArrayList<TaskDTO> list = taskService.updateTask(taskDTO, loginUser);
model.addAttribute("list", list);
page = "task/taskList";
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("msg", "할일 업데이트 실패");
page = "redirect:/task/list";
}
return page;
}
@PostMapping("/taskDelete")
public String deleteTask(@RequestBody Map<String, String> data, Model model, HttpSession session) {
UserDTO loginUser = (UserDTO) session.getAttribute("loginUser");
TaskDTO taskDTO = new TaskDTO();
System.out.println(data.get("btn"));
String page = "";
taskDTO.setTaskId(data.get("taskId"));
try {
ArrayList<TaskDTO> list = taskService.deleteTask(taskDTO, loginUser);
page = "task/taskList";
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("msg", "할일 삭제 실패");
page = "redirect:/task/list";
}
return page;
}
}
@Repository
public class TaskDAO {
public ArrayList<TaskDTO> selectTaskList(SqlSession sqlSession, UserDTO loginUser) throws Exception {
return (ArrayList) sqlSession.selectList("taskMapper.selectTaskList", loginUser);
}
public int insertTask(SqlSessionTemplate sqlSession, TaskDTO taskDTO) {
return sqlSession.insert("taskMapper.insertTask", taskDTO);
}
public int updateTask(SqlSessionTemplate sqlSession, TaskDTO taskDTO) {
return sqlSession.update("taskMapper.updateTask", taskDTO);
}
public int deleteTask(SqlSessionTemplate sqlSession, TaskDTO taskDTO) {
return sqlSession.delete("taskMapper.deleteTask", taskDTO);
}
}
public class TaskDTO {
private String userId;
private String taskId;
private String content;
private String complete;
private Date createdDate;
public TaskDTO() {
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getComplete() {
return complete;
}
public void setComplete(String complete) {
this.complete = complete;
}
@Override
public String toString() {
return "TaskDTO [userId=" + userId + ", taskId=" + taskId + ", content=" + content
+ ", complete=" + complete + "]";
}
}
public interface TaskService {
public int insertTask(TaskDTO taskDTO) throws Exception;
public ArrayList<TaskDTO> selectTaskList(UserDTO loginUser) throws Exception;
public ArrayList<TaskDTO> updateTask(TaskDTO taskDTO, UserDTO loginUser) throws Exception;
public ArrayList<TaskDTO> deleteTask(TaskDTO taskDTO, UserDTO loginUser) throws Exception;
}
@EnableAspectJAutoProxy
@Service
public class TaskServiceImpl implements TaskService {
private TaskDAO taskDAO = new TaskDAO();
private SqlSessionTemplate sqlSession;
@Autowired
public TaskServiceImpl(TaskDAO taskDAO, SqlSessionTemplate sqlSession) {
super();
this.taskDAO = taskDAO;
this.sqlSession = sqlSession;
}
@Override
public int insertTask(TaskDTO taskDTO) {
int reult = taskDAO.insertTask(sqlSession, taskDTO);
return reult;
}
@Override
public ArrayList<TaskDTO> selectTaskList(UserDTO loginUser) throws Exception {
ArrayList<TaskDTO> list = taskDAO.selectTaskList(sqlSession, loginUser);
return list;
}
@Transactional(rollbackFor = Exception.class)
@Override
public ArrayList<TaskDTO> updateTask(TaskDTO taskDTO, UserDTO loginUser) throws Exception {
int result = taskDAO.updateTask(sqlSession, taskDTO);
if (result <= 0) {
throw new Exception("task 업데이트 실패!");
}
ArrayList<TaskDTO> list = taskDAO.selectTaskList(sqlSession, loginUser);
return list;
}
@Transactional(rollbackFor = Exception.class)
@Override
public ArrayList<TaskDTO> deleteTask(TaskDTO taskDTO, UserDTO loginUser) throws Exception {
int result = taskDAO.deleteTask(sqlSession, taskDTO);
if (result <= 0) {
throw new Exception("task 업데이트 실패!");
}
ArrayList<TaskDTO> list = taskDAO.selectTaskList(sqlSession, loginUser);
return list;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="taskMapper">
<resultMap type="taskDTO" id="taskResultSet">
<!-- 언더바가 들어가는 쿼리문에 한하여 매핑을 해줘야함 -->
<id property="userId" column="user_id" />
<result property="taskId" column="task_id" />
<result property="content" column="content" />
<result property="complete" column="complete" />
<result property="createdDate" column="create_date" />
</resultMap>
<select id="selectTaskList" parameterType="userDTO"
resultMap="taskResultSet">
SELECT *
FROM TASK
WHERE user_id = #{userId}
order by
create_date
</select>
<insert id="insertTask" parameterType="taskDTO">
insert into task
(user_id,
task_id, content)
values
(#{userId}, #{taskId},#{content})
</insert>
<update id="updateTask" parameterType="taskDTO">
update task
set complete =
#{complete}
where task_id = #{taskId}
</update>
<delete id="deleteTask" parameterType="taskDTO">
delete from task
where task_id =
#{taskId}
</delete>
</mapper>

저장 버튼을 누르면 DB task테이블에 저장이 되고 화면 이동없이 일정리스트가 다시 렌더링된다.

'과제 제출하기' 완료 버튼을 누르면, 회색으로 input창의 배경색이 변경되고 버튼 역시 취소 버튼으로 바뀐다. 물론 DB에도 isComplete가 'Y'로 바뀐다.

'저녁먹기' 일정을 삭제해보자. DB에서 삭제되고 taskList를 다시 비동기적으로 불러들여 화면 이동없이 렌더링된다.

본 포스팅은 멀티캠퍼스의 멀티잇 백엔드 개발(Java)의 교육을 수강하고 작성되었습니다.