요구사항은 “개인정보 수정”이다.
즉 로그인한 사용자가 자기 정보(이름/이메일/비밀번호 등)를 수정할 수 있어야 한다.
또한 다른 사용자의 정보를 수정할 수 없어야 한다.
그리고 수정 화면에는 기존 정보가 미리 채워져 보여야 한다.
이 기능은 “화면을 보여주는 단계”와 “수정 내용을 저장하는 단계”로 나뉜다.
전체 흐름
개인정보 수정은 다음 순서로 동작한다.
- 사용자 목록(또는 프로필 화면)에서 “수정” 버튼을 누른다
- 서버가 기존 사용자 정보를 찾아서 수정 폼 화면에 미리 채워서 보여준다
- 사용자가 브라우저에서 값을 바꾼 뒤 “수정” 버튼을 누른다
- 브라우저가 수정된 값들을 POST 요청으로 서버에 보낸다
- 저장소`DataBase`에 수정 내용을 반영한다
- 수정이 끝나면 목록`/user/list` 또는 메인`/`으로 리다이렉트한다
핵심은 이 2개다.
- 수정 화면(GET): 기존 정보를 보여주기 위한 단계다
- 수정 저장(POST): 사용자가 바꾼 정보를 실제로 저장하는 단계다
수정 버튼 클릭
목록 화면 `list.jsp`의 수정버튼 부분을 보면
<td><a href="/user/updateForm?userId=${user.userId}" class="btn btn-success" role="button">수정</a></td>
이렇게 되어있다.
즉, 수정 버튼을 누르면 보통 이런 요청이 간다.
GET /user/updateForm?userId=woojoo
여기서 `userId=woojoo`는 “수정할 대상 사용자”를 식별하기 위한 값이다.
서블릿의 doGet()은 이 요청을 받아서 다음 작업을 해야 한다.
- userId를 꺼낸다
- 저장소에서 해당 userId의 사용자(User)를 찾는다
- JSP가 그 사용자 정보를 사용할 수 있도록 request에 담는다
- updateForm.jsp로 forward하여 화면을 렌더링한다
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userId = req.getParameter("userId");
User user = DataBase.findByUser(userId);
req.setAttribute("user", user);
RequestDispatcher rd = req.getRequestDispatcher("/user/updateForm.jsp");
rd.forward(req, resp);
}
forward()는 “JSP 파일로 이동한다”가 아니라,
서버 내부에서 JSP를 실행시켜 HTML을 만들어서 응답한다는 뜻이다.
2026.02.06 - [Backend/Servlet] - forward와 JSP 실행 흐름
개인정보 수정 화면(JSP)은 “기존 값이 채워진 폼”이어야 한다
요구사항이 “개인정보 수정”이라면 화면은 이런 형태가 되어야 한다.
- userId는 “변경 불가”다
- name/email은 현재 값이 input에 미리 들어가 있어야 한다
- password는 보안상 화면에 뿌리지 않고 빈칸으로 두는 것이 안전하다
- 그리고 서버에서 “비어있으면 기존 비번 유지” 규칙을 적용한다
1) userId를 hidden으로 고정하는 이유
개인정보 수정에서 userId는 사실상 “사용자 식별자(키)”다.
- userId가 바뀌면 “수정”이 아니라 “다른 사용자로 저장”이 될 수 있다
- Map 구조에서는 키가 바뀌면 새 데이터로 추가된다
그래서 화면에서는 `userId`를 이렇게 처리한다.
- 화면에는 텍스트로 보여준다(읽기 전용)
- 전송할 때는 hidden으로 보낸다(값 고정)
<input type="hidden" name="userId" value="${user.userId}" />
<div class="form-group">
<label>사용자 아이디</label>
${user.userId}
</div>
2) name/email은 value로 기존값을 넣는다
이것이 “수정 화면”의 핵심이다.
<input class="form-control" id="name" name="name" value="${user.name}">
<input class="form-control" id="email" name="email" value="${user.email}">
여기서 `${user.name}`은 “서버 `doGet`에서 `request`에 넣어준 `user`”의 값이다.
- 서버가 최초 화면을 만들 때 input의 초기값을 “철수”로 채워준다
- 브라우저는 그 HTML을 받아서 화면에 “철수”가 들어있는 input을 보여준다
- 사용자가 브라우저에서 “철수”를 “영희”로 바꾸면
- 바뀌는 것은 JSP 파일이 아니라 브라우저 input의 값이다
- submit을 누르면 브라우저가 “현재 input 값”을 POST로 보낸다
즉 POST로 전송되는 값은 JSP 코드에 적힌 “철수”가 아니라,
브라우저에서 사용자가 바꾼 “영희”다.
3) password는 빈칸으로 두는 게 기본이다
비밀번호를 화면에 출력하면 보안상 위험하다.
따라서:
<input type="password" class="form-control" id="password" name="password" placeholder="Password">
이렇게 빈칸으로 둔다.
개인정보 수정 저장은 POST로 처리한다
사용자가 수정 버튼을 누르면 브라우저는 POST 요청을 보낸다.
POST /user/update
`form` 안에 있는 `input`들이 전송된다.
- hidden의 userId
- name
- password (입력했으면 값, 안 했으면 빈 값)
이 요청을 서블릿의 doPost()가 처리한다.
최종 doPost 구현
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1) POST 한글 입력 깨짐 방지
req.setCharacterEncoding("UTF-8");
// 2) 어떤 사용자를 수정할지 식별
String userId = req.getParameter("userId");
// 3) 기존 사용자 조회
User origin = DataBase.findByUser(userId);
if (origin == null) {
throw new IllegalStateException("존재하지 않는 사용자입니다.");
}
// 4) 비밀번호 정책: 입력 안 하면 기존 비밀번호 유지
String password = req.getParameter("password");
if (password == null || password.isBlank()) {
password = origin.getPassword();
}
// 5) 수정 반영할 객체 생성 (또는 origin.update(...) 방식)
User updated = new User(
userId,
password,
req.getParameter("name"),
req.getParameter("email")
);
// 6) 저장소에 반영
// DataBase가 Map이면 같은 userId로 put되어 덮어쓰기(수정)가 된다.
DataBase.addUser(updated);
// 7) 완료 후 목록으로 이동
resp.sendRedirect("/user/list");
}
출처 : 《자바 웹 프로그래밍 Next Step》, 박재성, 로드북
'Book > 자바 웹 프로그래밍 Next Step' 카테고리의 다른 글
| 6장_ 요구사항4 : 회원 목록 및 개인정보 수정 보안 강화 (0) | 2026.02.07 |
|---|---|
| 6장_ 요구사항3 : 세션 기반 로그인/로그아웃 상태 만들기 (0) | 2026.02.07 |
| 6장_ : ListUser 화면 구현 (0) | 2026.02.06 |
| 6장_ : ListUSerServlet 구현 (0) | 2026.02.06 |
| 5장_ : 서블릿 컨테이너가 하는 일: 생명주기와 인스턴스 생성 (0) | 2026.02.05 |
