[Project] Todolist Web Service

개발 환경은 Eclipse Maven Project 에서 서블릿과 jsp 를 사용했다.
jsp를 이용하면 html 코드와 java 코드를 쉽게 섞어 쓸 수 있다. 그래도 프론트엔드 개발자와의 이해를 돕기 위해 최대한 java 코드를 줄이는 쪽으로 짜는 것이 좋은 코드라고 한다.
먼저 vs code에서 전체 구조를 html과 css 코드를 이용해 구현하는 것 부터 시작했다.


리스트가 하나씩 추가 될 때마다 쉽게 추가하고 관리하기 위해 table로 만들어줬다. 원래 리스트의 '할일'과 아래의 '날짜' '우선순위' 등의 항목들을 서로 다른 tr 태그에 넣고 관리했는데 아무래도 불편한 것 같아 하나의 tr에 넣는 방식으로 수정했다.
css는 아무리해도 아직 어려운 것 같다. float 속성으로 적절히 배치하는 것, 각 리스트 카드의 간격을 맞추는 것 등 크롬 개발자 도구를 활용해 하나하나 바꿔본 끝에 완성할 수 있었다. 제목은 돌려서 구현해야 해서 transform 속성의 rotate를 이용했다.


#title {
    color: #9e6d22e7;
    transform:rotate(-30deg);
    transform-origin: 70% 0%; 
    font-weight: bold;
    float:left;
    font-size:35px;
}
...

나는 mysql db에서 데이터를 불러와서 type (todo, doing, done) 에 따라 각각을 리스트에 담아 메인 화면에 각각 출력하는 방식을 사용했는데 반복문을 돌면서 할 수 있을까 생각하다 잘 생각이 안나서 따로 써주었다. 다시 한번 코드를 간결화 하기 위해 어떤 방법이 있을지 연구해봐야겠다 ..


 <div id="lists">
        <div class="outside">
   <div class="section">TODO </div>
            <table id="TODO">
            <%
              List<TodoDto> todo = new ArrayList<>();
              todo = (List<TodoDto>)request.getAttribute("todo");
             %>
             <c:forEach items="${todo }" var="item">
             <tr id="list${item.id }"><td>
              <span class="up">${item.title }</span><br>
              <span class="sub">등록날짜 : ${item.regDate }, ${item.name }, 
              우선순위 ${item.sequence }<button type="button" id="btn${item.id }" 
              onclick="changeType(${item.id})" ></button></span>
             </td></tr>
             </c:forEach>
....


java 코드를 줄이기 위해 EL과 jstl 코드를 적절히 사용했다.

TodoDao와 TodoDto 패키지를 만들고 구현했다.
Dto에는 리스트 객체를 만들어두었다. type을 String 객체로 사용했는데 이것보다 enum을 사용하는 것이 오타가 나는 것을 방지 할 수 있을 것 같아 수정했다.


[Type.java]


public enum Type {
 TODO, DOING, DONE
}

[TodoDto.java]


public class TodoDto {

 private long id;
 private String name;
 private String regDate;
 private int sequence;
 private String title;
 private Type type;

private 인자들에 대한 getter setter를 모두 선언해주었다가 사용하지 않는 setter 메서드는 모두 없앳다. getter는 상관없지만 setter는 변수 값을 바꿀 수 있는 메서드이므로 private으로 선언한 인자에 대해서는 신중히 만들어야 한다.

다음으로 db Connection에 관련된 dburl, user, passsword와 같은 변수들을 dao 파일 내에서 변수로 선언해주었는데 이런 개인정보와 외부 url endpoint 같은 값들은 시스템 설정 값들이므로 코드 밖에서 관리하는 것이 가독성도 더 좋고 추후 개발용, 로컬용, 리얼용으로 설정이 나뉘었을때 관리가 용이하게되도록 properties 파일로 관리하는 것이 더 좋다는 말을 듣고 properties 파일을 만들어줬다.

WEB-INF 내에 classes 폴더를 만들어 파일을 생성해놓으면 이후 class loader가 파일을 읽어올 수 있다. property 파일은 key = value 형식으로 만들면 된다.


dburl=jdbc:mysql://localhost:3306/todolist?useSSL=false
dbUser=todouser
dbpasswd=1234

database에 접속하는 코드가 계속해서 쓰이므로 따로 빼놓았는데 안그랬다면 하나하나 다 바꿔줘야 할 뻔 했다. 수정된 properties 파일을 불러오는 부분을 connect 하는 메서드 안에 추가해줬다.


public Connection connectDB() {
  Connection conn = null;
  try {
   Class.forName("com.mysql.jdbc.Driver");

  } catch (ClassNotFoundException e) {

   e.printStackTrace();
   System.out.println("Fail to connect your DB.");
  }
  props = new Properties();
  try {
   props.load(this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE));
  } catch (IOException e) {
   System.out.println("Properties File Load Fail");
   e.printStackTrace();
  }
  try {
   conn = DriverManager.getConnection(props.getProperty("dburl"), props.getProperty("dbUser"),
     props.getProperty("dbpasswd"));
  } catch (SQLException e) {
   e.printStackTrace();
   System.out.println("Fail to connect db with given info");
  }
  return conn;
 }

그리고 단계 하나하나 다른 exception을 잡도록 해줬다. 원래는 하나의 메서드에 모두 try 하고 Exception 객체 하나로 받았다. 하지만 어떤 오류가 발생하는지에따라 처리 방법도 달라져야 하기때문에 상황에 적절한 예외 catch문을 써줬다.

todo와 doing 섹션에 있는 카드들의 버튼을 누르면 doing, done으로 이동시켜주고 done으로 이동시에 버튼을 없애줘야 했다. 새로고침없이 실행되어야 했기 때문에 비동기 통신 Ajax를 이용했다. 여기서 정말 많이 헤매었다. 그 과정에서 POST와 GET 방식에 대한 확실한 이해를 했다.


<script type="text/javascript">
 function changeType(tid) {
     var xhr = new XMLHttpRequest();
     xhr.open('GET',"/TodoList/type?id="+encodeURI(tid),true);
     xhr.addEventListener("load",function(){
      
         var tr = document.getElementById('list'+tid);
         var p_tbl = tr.parentNode.parentNode;
       
         if(p_tbl.id=="TODO") 
          var n_tbl = document.getElementById("DOING");
         else 
          var n_tbl = document.getElementById("DONE");
         
         if(n_tbl.id=="DONE"){
          var btn = document.getElementById("btn"+tid)
             btn.parentNode.removeChild(btn);
         }
         
         n_tbl.appendChild(tr);
     })
     xhr.send();
 }
 </script>

Ajax를 사용하기위해서는 XMLHttpRequest 객체가 필요하다. GET 방식으로 버튼을 누른 카드 엘리먼트의 id를 카드의 이동을 수행하는 서블릿클래스의 url(/type)로 보낸다. 요청이 성공적으로 보내지면 appendChild()메서드를 이용해 이동할 섹션의 밑으로 카드를 이동한다.
처음에는 post 방식으로 보내려했는데 주로 GET을 사용하며 POST 방식은 중요한 정보 또는 form 정보를 보낼때 사용한다는 것을 알게되어 GET을 사용하였다.

git lab에 코드 첨삭을 위해 업로드 했는데 지난 첨삭을 참고해 이번에는 .gitignore 파일을 만들어 코드를 업로드했다. 하지만 target 디렉토리도 필요가 없다는 것을 듣고 캐시를 삭제, gitignore 에 아래 코드 추가 후 새로 커밋을 해놓았다.


#.gitignore

target/


Ajax 구현에서 가장 시간이 오래걸렸다. 아직 JavaScript에 대한 이해도가 떨어지는 것 같아 더 공부해야겠다는 생각이 들었다. 그래도 하나 완성했다!



No comments:

Powered by Blogger.