SpringBoot를 이용한 mvc2 TodoList 구현
저번주부터 4일 동안 진행한 미니 프로젝트에 대해서 정리하고자 한다.
사용한 기술 : Spring / SpringBoot / MyBatis / MariaDB / JSP
이용한 객체 : DTO / DAO / Service / Controller / View
현재까지 구현한 기능 : CRUD / 페이징처리 / 검색
추가로 구현이 필요한 기능 및 기술 : Log4j2 / Validation / 파일 업로드 기능 / 로그인(원래는 비회원 게시판!)
[첫째날 진행했던 과정과 고민했던 부분들]
생각보다 진행할 수 있는 시간이 많지 않아서 페이징 처리를 하지 않은 전체 list 조회 기능과 리스트 뷰 화면을 만드는데까지 진행하였다. 새로 배웠던 부분은 '부트스트랩'이라는 건데 기본적인 프론트 부분들을 간편하게 사용할 수 있도록 오픈 소스를 제공해주는 프레임워크이다. 화면의 기본적인 부분들을 깔끔하게 정리할 수 있도록 해주는 기술인데 사이트에서 제공해주는 html을 그대로 가져와서 name, id 등 최소의 수정만 해주면 간편하게 데이터들을 불러와서 사용할 수 있도록 해주는 프레임워크다. 사실 백엔드 과정을 중점으로 배우는 우리에겐 너무 큰 도움이 됐던 부트스트랩이지만 처음 사용해보는 입장에서는 생각보다 까다로운 부분도 많았던 것 같다. 수많은 꺽새들을 보는 것만으로도 머리가 어지러웠지만 강사님의 코드가 아닌 우리만의 코드로 화면을 구성해보는 것이 중요하다고 생각해서 어떻게든 list 페이지를 만들고자 노력했다. 그 외에 백에서의 list 기능 구현은 매우 간편했기에 첫날은 부트스트랩과 친해지는 시간 정도로 정리할 수 있을 것 같다.
[둘째날 진행했던 과정과 고민했던 부분들]
둘째날부터 modify, view 화면을 먼저 하나하나 만들고 CRUD 기능 구현까지를 목표로 잡고 진행했다. 순조롭게 진행되던 중 생각지 못한 부분에서 브레이크가 걸렸는데 list에서 특정 객체의 데이터를 보기위해서 view 페이지로 넘어가고 거기서 modify로 넘어가는 과정에서 데이터의 값이 넘겨지지 않아서 한참을 헤맸던 것 같다. modify 페이지로 넘어가는 부분은 get방식을 통해서 매핑을 해줬는데 새로 입력받는 값 없이 그대로 데이터를 넘겨주는 방법을 잘 몰랐다. jsp에서 <c:forEach>를 이용해서도 시도해보고 파라미터 값들을 하나하나 불러와서도 시도해보고 아예 DTO의 값을 getter로 불러와서도 해봤는데 답은 jsp에 있었다. 처음에 우리는 <form> 태그를 통해서 <input type = "submit"> 으로 modify 버튼을 만들어줬는데 그렇게 하니까 받아오는 데이터는 없는데 submit이 돼서 안 됐던 거였다. 이걸 <a href> 로 바꿔주니 간단하게 해결이 되었다.
<- 원했던 결과물
실제 나왔던 결과물 ->
[셋째날 진행했던 과정과 고민했던 부분들]
웬만한 기능들을 전부 구현하고 페이징 처리와 검색 기능까지 구현을 했던 날이다. 페이징 처리하는 과정이 매우 복잡하고 어려웠는데 수업자료의 힘을 좀 많이 빌렸다. RequestDTO와 ResponseDTO를 새로 만들어서 페이징 처리할 변수들을 집어넣어줬는데 respontDTO에서 개인적으로 이해하기 힘들었던 부분이 있었다. 각각의 변수들이 정확하게 어떤 의미를 가지는지, pageResponseDTO 생성자는 어떤 값들을 가지는지 수식을 이해하기가 무척 힘들었는데 단순히 말로 표현하면 이해가 가는데 이걸 변수와 식으로 표현하니 머리가 너무 아팠다. start와 end는 페이지 묶음(1~10 / 2~20 ...)의 시작과 끝값이고 last는 전체의 마지막 페이지라는걸 이해하고 내것으로 만드는데 시간이 오래 걸렸다.
@Data
public class PageResponseDTO<E> {
private int page; // 현재 페이지
private int size; // 한 페이지당 갯수
private int total; // 전체 글 갯수
//한그룹의 시작페이지 넘버
private int start;
//한그룹의 끝 페이지 넘버
private int end;
//이전 페이지그룹 존재여부
private boolean prev;
//다음 페이지그룹 존재여부
private boolean next;
private List<E> dtoList;
@Builder(builderMethodName = "withAll")
public PageResponseDTO(PageRequestDTO pageRequestDTO, List<E> dtoList, int total) {
this.page = pageRequestDTO.getPage();
this.size = pageRequestDTO.getSize();
this.total = total;
this.dtoList = dtoList;
this.end = (int)(Math.ceil(this.page/10.0))*10; // 31/10 -> 3.1 -> 4 -> 40
this.start = this.end - 9; //31
int last = (int)(Math.ceil((total/(double)size))); // 330/10 34(총페이지 수)
this.end = end > last ? last : end;
this.prev = this.start > 1;
this.next = total > this.end * this.size; //40 * 10 = 400
}
}
크게 고민했던 부분들이 몇가지가 있는데
첫째, 검색 기능을 구현할 때 Mybatis를 이용한 동적쿼리
둘째, 하나의 데이터를 읽고 다시 리스트로 돌아왔을 때 페이지 정보가 유지되지 않는 점
셋째, 현재 페이지가 아닌 다른 페이지에서 검색을 했을 때 유효한 데이터 값이 나오지 않는 점
넷째, 검색한 결과의 페이징 처리가 제대로 되지 않는 점 -> 다음 페이지를 누르면 검색 내용이 초기화되는 점
먼저 첫번째 부분은 동적쿼리에 대해서 제대로 배우지 않았다는게 제일 문제였다. 실제 짜여진 쿼리를 봐도 이해가 가지 않았고 각각이 의미하는 부분이 무엇인지, 그걸 어떤식으로 활용해서 우리의 코드와 맞게 리팩토링 할 수 있을지 고민을 많이 했고 이 부분은 차차 조원들과 같이 공부하면서 지식을 쌓아가기로 마무리했다.
두번째, 세번째 부분의 모든 해결책은 jsp에 있었는데 자바스크립트를 이용해서 url에서 강제로 page정보를 받아서 넘어갈 수 있도록 처리해줄 수 있었다. 이 부분을 빠르게 생각하지 못했던 원인 역시 자바스크립트에 대한 지식이 부족해서였는데, 1월에 조금 공부를 하고 넘어갔던 터라 기억도 흐릿했었고 자바스크립트를 다시 빡세게 공부해야겠다는 생각이 들었다. 이번주부터 Node.js를 배우니까 자바스크립트에 대해서 더 공부할 수 있을 것이다!
대망의 네번째 부분인데 이 부분은 사실 저날 마무리하지 못했다... 페이징처리까지는 DAO에 searchCount 메소드를 만들어서 검색 결과 데이터의 갯수를 반환하도록 만들어서 해결하였다. (아래 코드 참고)
<select id="searchCount" resultType="_int">
select count(tno) from tbl_todo
<where>
<if test="types != null and types.length > 0">
<foreach collection="types" item="type" open="(" close=") " separator=" OR ">
<if test="type == 't'.toString()">
title like concat('%', #{searchContent}, '%')
</if>
<if test="type == 'w'.toString()">
writer like concat('%', #{searchContent}, '%')
</if>
</foreach>
</if>
<if test="finished">
<trim prefix="and">
finished = 1
</trim>
</if>
<if test="startDate != null and endDate != null">
<trim prefix="and">
dueDate between #{startDate} and #{endDate}
</trim>
</if>
</where>
</select>
그러나 2페이지를 누르면 모든 검색 값들이 초기화되면서 원래 list 페이지로 돌아가게 됐고, url에서 현재 검색 적용된 값들을 하나도 받아오지 못해서 생기는 문제 같은데 그 부분을 아무리 머리를 맞대고 고민해도 해결할 수 없어서 일단 검색 페이징 처리까지 구현한 것에 만족하고 마무리하기로 했다. 이 부분은 오늘 극적으로 해결하게 되었는데 그 부분은 추후에 프로젝트 수정 부분들을 하나씩 빌드업하면서 같이 포스팅하도록 하겠다.
금방 끝낼 수 있을거라 생각했던 프로젝트였는데 생각보다 너무 어렵고 디테일한 부분들까지 잡아야할게 많아서 역시 만만치 않구나..란 생각을 했던 것 같다. 곧 메인 프로젝트에 들어갈건데 설계 단계에서부터 준비를 탄탄하게 해야할 것 같다. 비회원 게시판 사이트를 만드는데도 아주 세세하고 디테일한 부분들까지 잡는게 힘들다는걸 뼈저리게 느꼈는데 실제 사용자들이 사용할 수 있는 사이트를 만드는건 얼마나 꼼꼼하게 생각해야할까? 과정을 진행하면서 점점 책임감을 많이 느끼고 있고 이런저런 생각들이 많아지는 것 같다. 꼭 유용하고 사용자들이 편하게 사용할 수 있는 사이트를 만들어내야지!!!
