Day 36 - Servlet
이 글은 2026년 04월 21일 작성된 글입니다.
오늘은 홈 화면 추가, 게시물 수정과 삭제 처리, 공통 템플릿 분리, 그리고 회원가입 기능까지 정리했다.
1. HomeServlet 도입
애플리케이션의 시작 화면을 담당하는 HomeServlet을 도입했다.
홈 화면이 생기면 사용자가 처음 접속했을 때 어디로 이동해야 하는지 더 자연스럽게 안내할 수 있다.
@WebServlet("/")
public class HomeServlet extends HttpServlet {
}- 시작 페이지 역할
- 전체 흐름의 진입점 정리
2. 게시물 수정 폼 구현
기존 게시물을 수정할 수 있도록 수정 폼을 만들었다.
수정 폼은 작성 폼과 비슷하지만, 이미 존재하는 데이터를 보여준 뒤 사용자가 변경할 수 있게 하는 점이 다르다.
<form method="POST">
<input type="text" name="title" value="기존 제목">
<textarea name="content">기존 내용</textarea>
<button type="submit">수정</button>
</form>- 기존 데이터를 입력창에 미리 채워둠
- 사용자는 필요한 부분만 수정 가능
3. 게시물 수정 폼 처리
수정 화면만 만드는 것으로 끝나는 것이 아니라 폼에서 전달된 데이터를 실제로 처리하는 로직도 필요하다.
GET /usr/article/modify
POST /usr/article/modify- GET 요청은 수정 폼 노출
- POST 요청은 수정 데이터 처리
작성 기능과 마찬가지로 수정도 화면 출력과 실제 처리를 나누는 구조로 설계했다.
4. 수정 폼에 기존 데이터 받아오기
수정 폼이 제대로 동작하려면 어떤 게시물을 수정하는지 먼저 알아야 한다.
그래서 상세페이지나 리스트에서 넘겨준 게시물 번호를 기준으로 기존 데이터를 조회하고, 그 값을 폼에 채워 넣었다.
<input type="text" name="title" value="${article.title}">
<textarea name="content">${article.content}</textarea>이 과정이 있어야 사용자는 빈 폼이 아니라 기존 내용이 들어 있는 상태에서 수정할 수 있다.
- 수정 대상 게시물 조회
- 기존 값 화면에 출력
5. 게시물 수정 처리
사용자가 수정한 값을 제출하면 서버는 전달받은 게시물 번호를 기준으로 기존 데이터를 변경한다.
- 제목 수정
- 내용 수정
- 수정일 갱신 가능
이제 게시물은 단순히 생성하고 조회하는 수준을 넘어서 실제로 변경 가능한 상태가 되었다.
6. 액션 처리 후 페이지 전환
수정이나 삭제 같은 작업을 처리한 뒤에는 사용자를 적절한 페이지로 다시 보내줘야 한다.
이번에는 location.replace()와 history.back()을 활용해
액션 처리 후 페이지 전환 흐름을 만들었다.
<script>
location.replace("/usr/article/list");
</script><script>
history.back();
</script>- 성공 후 목록이나 상세페이지로 이동
- 실패 시 이전 페이지로 돌아가기 가능
이 방식은 사용자가 액션 이후 어디로 가야 하는지 명확하게 해준다.
7. 게시물 삭제 처리
게시물 삭제 기능도 구현했다.
삭제는 수정과 다르게 데이터를 바꾸는 것이 아니라 아예 제거하는 작업이기 때문에 더 조심해서 다뤄야 한다.
- 전달받은 게시물 번호 확인
- 해당 게시물 존재 여부 검증
- 삭제 처리 후 적절한 페이지 이동
이제 게시물 CRUD 흐름이 거의 완성되었다.
8. 삭제는 GET보다 POST가 더 적절한 이유
삭제는 데이터에 변화를 주는 작업이기 때문에 원칙적으로는 GET보다 POST 방식이 더 적절하다.
GET 요청은 조회 성격에 가깝고, 삭제처럼 서버 상태를 바꾸는 작업에는 맞지 않는다.
그래서 이번에는 삭제를 위한 별도의 form을 두는 방식으로 처리했다.
<form method="POST" action="/usr/article/delete">
<button type="submit">삭제</button>
</form>- GET은 조회용
- POST는 상태 변경 처리용
이 차이를 이해하는 것은 REST와 HTTP 메서드의 의미를 제대로 이해하는 데도 중요하다.
9. hidden input으로 삭제 id 전달
삭제 버튼만 누른다고 어떤 게시물을 지울지 알 수는 없다. 그래서 hidden input을 사용해 삭제할 게시물 id를 요청 바디에 담아 보냈다.
<form method="POST" action="/usr/article/delete">
<input type="hidden" name="id" value="${article.id}">
<button type="submit">삭제</button>
</form>이 방식은 화면에는 보이지 않지만 서버에는 필요한 데이터를 함께 전달할 수 있어서 많이 사용된다.
- 사용자에게는 안 보임
- 서버에는 필요한 값 전달 가능
10. 공통 템플릿 분리
여러 페이지에 반복해서 들어가는 상단과 하단을 공통 템플릿으로 분리했다.
header.jspfooter.jsp
<%@ include file="/jsp/common/header.jsp" %><%@ include file="/jsp/common/footer.jsp" %>이렇게 분리하면 모든 페이지에 같은 레이아웃을 쉽게 적용할 수 있고, 수정도 한 곳만 바꾸면 전체에 반영된다.
- 중복 코드 감소
- 레이아웃 관리 편의성 증가
11. 회원가입 폼 구현
이제 게시물 기능만이 아니라 회원 기능도 본격적으로 들어가기 시작했다.
회원가입 폼에서는 보통 다음 값을 입력받는다.
- 아이디
- 비밀번호
- 이름
<div class="container">
<h2>회원 가입</h2>
<form method="POST" action="#">
<div class="form-group">
<label for="username">아이디</label>
<input type="text" id="username" name="username" placeholder="아이디를 입력해주세요" required>
</div>
<div class="form-group">
<label for="password">비밀번호</label>
<input type="password" id="password" name="password" placeholder="비밀번호를 입력해주세요" required>
</div>
<div class="form-group">
<label for="name">이름</label>
<input type="text" id="name" name="name" placeholder="이름을 입력해주세요" required>
</div>
<button type="submit">회원가입</button>
</form>
</div>폼을 직접 구현해보면 단순히 입력창을 만드는 것뿐 아니라 어떤 데이터를 어떤 이름으로 서버에 보낼지까지 고민하게 된다.
12. 회원가입 폼 처리
회원가입 폼을 만들었다면 이제 사용자가 입력한 값을 실제로 처리해야 한다.
- username 받기
- password 받기
- name 받기
- 회원 데이터 저장
이 단계부터는 게시물 기능에서 만들었던 Controller → Service → Repository 흐름이 회원 기능에도 그대로 확장될 수 있다.
기능은 달라도 구조는 재사용할 수 있다는 점이 중요하다.
✅ 정리
- 수정 기능은 기존 데이터를 폼에 채워 넣고 다시 저장하는 흐름으로 동작한다.
- 삭제 기능은 GET보다 POST가 더 적절하며, hidden input으로 필요한 id를 함께 전달할 수 있다.
- header.jsp와 footer.jsp를 분리하면서 화면 구성의 중복을 줄일 수 있었다.
- 게시물 기능을 만들던 흐름이 회원가입 기능에도 자연스럽게 확장되기 시작했다.