Skip to content

최현식 6주차 JSP 서블릿 학습 일지

HyeonSik Choi edited this page Aug 7, 2024 · 6 revisions

정리

서블릿, DAO, Service 레이어로 구분되어있는 적당한 서블릿 프로젝트를 만들었습니다!

image

경험한 것들

JDBC 테스트를 위해 인메모리H2 활용하기

  • JDBC와 의존을 가지는 DAO를 테스트하기 위해 인메모리 H2 데이터베이스를 활용했습니다. 이 때, 각 테스트마다 독립성을 보장하기 위한 노력을 했습니다. 이를 위해 매 테스트마다 데이터베이스를 새로 생성할 수 있었지만, 새로운 데이터베이스가 생성되는 경우 테스트 시간이 매우 오래걸리기 때문에 이를 개선하기위해 DatabaseCleanup 구문을 테스트용으로 분리하고 이를 실행시켜 데이터베이스와 테이블 스키마는 유지한채 내부 데이터만 남겨두는 방식으로 테스트 시간을 감소시켰습니다.

Soft Deletion 구현

  • 게시글과 댓글을 실제로 Database에서 삭제하지 않고, 표시만 남기는 Soft Deletion을 적용하였습니다. 테이블 스키마에 is_deleted 필드를 추가하여 이를 통해 구분하였습니다. 추후에 이를 이용하여 데이터 복구 또는 히스토리 확인이 가능할 것 같습니다.

사용자 스크립트 실행 방지

  • CrossSite Scripting 공격을 방지하였습니다. 이를 위해 사용자 입력에 대한 출력을 jstl의 c:out을 통해 진행하였습니다. 또한 AJAX 스크립트를 사용하는 경우 사용자 입력을 필터링하고 HTML 태그 등을 이스케이프 처리 하였습니다.

인가를 어디서 확인하는 것이 좋을까? (각 Servlet vs Filter)

  • 현재 외부에서 확인한 Session의 User 정보를 Service.update로 넘기는 방식으로, 이후 Service 로직을 통해 행위를 할 권한이 있는 유저인지 확인하고 있습니다. 이에 대한 고민으로 현재처럼 각 서블릿+서비스에서 인가를 처리하는 것과, 공통의 필터를 두고 이를 처리하는 방법 중 어떤 것이 더 좋을지 고민이 되었습니다.
  • 넓은 의미에 인가(Role 같은)라면 Filter에서 처리해 줄 수 있을 것 같지만, 현재의 인가는 사용자 개개인 검증이라는 작은 의미를 가집니다. 즉, 현재 다루는 인가는 공통의 로직으로 뽑아내기에는 다소 무리가 있을 것 같아 현재 방식대로 진행하기로 하였습니다.
// 인증 확인  
final HttpSession session = request.getSession(false);  
final User sessionUser = (User) session.getAttribute("user");  
if (sessionUser == null) {  
    throw new LoginRequiredException("로그인이 필요한 작업입니다.");  
}  
  
// 동작  
Article article = new Article(articleId, sessionUser.getUserId(), title, contents);  
articleService.update(article, sessionUser.getUserId());

현재의 경우 아래 메서드를 보고 파라미터로 오는 userId를 무엇이라고 추측할 수 있을까?

// Service
public void update(Article article, String userId) {  
    Optional<Article> foundArticle = articleDao.findByArticleId(article.getId());  
    if (!foundArticle.isPresent()) {  
        throw new IllegalArgumentException("존재하지 않는 게시글입니다.");  
    }  
    if (!foundArticle.get().getWriter().equals(userId)) {  
        throw new AuthorizationException("유저 정보가 일치하지 않습니다.");  
    }  
  
    articleDao.update(article);  
}

Servlet을 처음에 모두 생성해도 괜찮을까?

  • 현재 서블릿에서 사용하는 멤버 변수들을 모두 private final 키워드로 선언하였으며, 이를 생성자에서 주입받도록 하였습니다. 이는 서블릿이 실제 불러와지는 시점에서 생성되어 init 메서드를 호출하는 방법과는 다른 방법으로, loadOnStartup과 동일한 상태가 되는 방식입니다. 생성자주입을 받기 위해 해당 방식을 사용했지만 이것이 괜찮은 방법인지 의문이 들었습니다.
  • 현재처럼 모든 서블릿을 애플리케이션 시작 시점에 모두 초기화하는 것은, 최초 시작 시간이 길어진다는 단점이 있습니다. 하지만 실제 요청 처리 시점에는 서블릿 초기화 시간이 없기 때문에 성능상에 이점이 될 수 있습니다. 또한 현재 서버 구조 상 활용되는 기능의 수가 작기 때문에 메모리 문제로 부터 안전하다고 생각하였습니다.
  • 따라서 서블릿을 lazy loading하지 않았을 때 생기는 단점보다, 구조적으로 얻는 장점이 크다고 생각하여 현재 방식을 선택했습니다.

마무리

재밌다!! 화이팅!!!

👼 개인 활동을 기록합시다.

개인 활동 페이지

🧑‍🧑‍🧒‍🧒 그룹 활동을 기록합시다.

그룹 활동 페이지

🎤 미니 세미나

미니 세미나

🤔 기술 블로그 활동

기술 블로그 활동

📚 도서를 추천해주세요

추천 도서 목록

🎸 기타

기타 유용한 학습 링크

Clone this wiki locally