JSP/Servlet을 공부하면서 가장 자주 만나게 되는 클래스가 HttpServletRequest와 HttpServletResponse이다.
Spring을 먼저 공부했던 입장에서는 처음에는 두 클래스가 낯설었지만, 생각보다 단순하다.
HttpServletRequest
= 클라이언트가 서버에 보낸 요청을 담고 있는 객체
HttpServletResponse
= 서버가 클라이언트에게 보낼 응답을 담는 객체
즉,
브라우저
│
│ Request
▼
Servlet
│
│ Response
▼
브라우저
라고 생각하면 된다.
Spring에서는 프레임워크가 많은 부분을 대신 처리해주기 때문에 직접 사용할 일이 상대적으로 적지만, Servlet에서는 이 객체들을 직접 다루게 된다.
HttpServletRequest는 클라이언트의 HTTP 요청 정보를 가지고 있는 객체이다.
Servlet의 doGet(), doPost()에서 다음과 같이 전달받는다.
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp
) throws ServletException, IOException {
}
여기서 req가 HttpServletRequest 객체이다.
주로 다음과 같은 작업에 사용한다.
1. 요청 파라미터 가져오기
2. Session 가져오기
3. JSP로 데이터를 전달하기
4. JSP 등 다른 자원으로 이동하기
HTML form이나 URL 등을 통해 전달된 요청 파라미터를 가져온다.
req.getParameter("파라미터명");
반환값은 String이다.
내 MemoProject의 SignUpServlet에서는 다음과 같이 사용했다.
String userId = req.getParameter("userId");
String userPw = req.getParameter("userPw");
String userName = req.getParameter("userName");
String userPwCheck = req.getParameter("userPwCheck");
사용자가 회원가입 화면에서 입력한 값을 Servlet이 가져오는 것이다.
흐름을 보면:
signUp.jsp
<input name="userId">
<input name="userPw">
<input name="userName">
↓ POST /signup
SignUpServlet
req.getParameter("userId")
req.getParameter("userPw")
req.getParameter("userName")
이다.
SignInServlet에서도 동일하다.
String userId = req.getParameter("userId");
String userPw = req.getParameter("userPw");
사용자가 입력한 아이디와 비밀번호를 가져온다.
메모 작성에서는:
String title = req.getParameter("title");
String content = req.getParameter("content");
처럼 제목과 내용을 가져온다.
Spring에서 다음과 같이 작성했다면:
@PostMapping("/signin")
public String signin(
@RequestParam String userId,
@RequestParam String userPw
) {
...
}
Servlet에서는 직접:
String userId = req.getParameter("userId");
String userPw = req.getParameter("userPw");
라고 가져온다고 생각하면 된다.
즉,
Spring
@RequestParam
↕
Servlet
req.getParameter()
라고 이해하면 편하다.
현재 요청의 Session을 가져온다.
HttpSession session = req.getSession();
Session이 없다면 새로운 Session을 생성한다.
내 SignInServlet에서는 로그인 성공 후:
HttpSession session = req.getSession();
session.setAttribute("loginMember", login);
을 사용했다.
즉:
로그인 성공
↓
User 객체
↓
HttpSession
↓
"loginMember"라는 이름으로 저장
하는 것이다.
이후 다른 Servlet에서도:
HttpSession session = req.getSession();
User loginMember =
(User) session.getAttribute("loginMember");
처럼 가져올 수 있다.
Spring에서도 HttpSession 자체는 사용할 수 있다.
HttpSession session
따라서 개념적으로는 동일하다.
다만 Servlet에서는 HttpServletRequest를 통해 직접 Session을 가져온다.
HttpServletRequest
↓
getSession()
↓
HttpSession
getSession()과 거의 비슷하지만 중요한 차이가 있다.
HttpSession session = req.getSession(false);
여기서 false는:
Session이 없으면 새로 만들지 마라.
라는 의미이다.
따라서 기존 Session이 없다면:
session == null
이 된다.
내 SignInServlet의 GET 요청에서는:
HttpSession session = req.getSession(false);
if (session != null) {
session.invalidate();
}
처럼 사용했다.
즉:
기존 Session이 있는가?
↓
있다
↓
Session 제거
기존 Session이 없는가?
↓
null
이다.
현재 request 객체에 데이터를 저장한다.
req.setAttribute("이름", 값);
주로 Servlet에서 JSP로 데이터를 전달할 때 사용한다.
req.setAttribute("memo", memo);
라고 저장한 뒤 JSP로 forward하면:
${memo.title}
처럼 사용할 수 있다.
흐름은:
Servlet
req.setAttribute("memo", memo)
↓
forward()
↓
JSP
${memo.title}
이다.
Spring MVC에서:
model.addAttribute("memo", memo);
를 사용하는 것과 비슷한 위치의 역할이다.
Spring
Model.addAttribute()
↕
Servlet
request.setAttribute()
완전히 동일한 API는 아니지만, Controller에서 View로 데이터를 전달한다는 관점에서 비교하면 이해하기 쉽다.
JSP 같은 다른 자원으로 요청을 전달하기 위한 RequestDispatcher를 얻는다.
RequestDispatcher dispatcher =
req.getRequestDispatcher("/WEB-INF/views/signIn.jsp");
그 후:
dispatcher.forward(req, resp);
를 호출한다.
내 SignInServlet에서는:
RequestDispatcher dispatcher =
req.getRequestDispatcher(
"/WEB-INF/views/signIn.jsp"
);
dispatcher.forward(req, resp);
를 사용했다.
흐름은:
GET /signin
↓
SignInServlet
↓
getRequestDispatcher()
↓
signIn.jsp
이다.
내 MemoProject에서 실제로 중요하게 사용했던 Request 메서드는 다음과 같다.
| 메서드 | 역할 | 사용 예 |
|---|---|---|
getParameter() | 요청 데이터 가져오기 | 로그인, 회원가입 |
getSession() | Session 가져오기/생성 | 로그인 |
getSession(false) | 기존 Session만 가져오기 | 로그인 페이지 |
setAttribute() | Request에 데이터 저장 | JSP 전달 |
getRequestDispatcher() | 다른 자원으로 이동할 Dispatcher 생성 | JSP 이동 |
HttpServletResponse는 반대로 서버가 클라이언트에게 보내는 HTTP 응답을 다루는 객체이다.
Servlet에서:
protected void doGet(
HttpServletRequest req,
HttpServletResponse resp
)
의 resp가 바로 Response 객체이다.
주로:
1. 다른 URL로 redirect
2. HTTP Response Header 설정
등에 사용한다.
클라이언트에게 다른 URL로 다시 요청하도록 지시한다.
resp.sendRedirect("/main");
회원가입 성공 후:
resp.sendRedirect("/signin");
을 사용했다.
흐름은:
POST /signup
↓
SignUpServlet
↓
회원가입 성공
↓
sendRedirect("/signin")
↓
브라우저가 다시 /signin 요청
↓
SignInServlet
이다.
로그인 성공 후:
resp.sendRedirect("/main");
을 사용한다.
POST /signin
↓
SignInServlet
↓
로그인 성공
↓
sendRedirect("/main")
↓
GET /main
↓
MainServlet
Spring에서는:
return "redirect:/main";
이라고 작성할 수 있다.
Servlet에서는:
resp.sendRedirect("/main");
이라고 직접 작성한다.
Spring
return "redirect:/main";
↕
Servlet
resp.sendRedirect("/main");
Servlet 공부에서 매우 중요한 부분이다.
dispatcher.forward(req, resp);
서버 내부에서 다음 자원으로 요청을 전달한다.
브라우저
↓
Servlet
↓
JSP
기존 Request를 그대로 사용할 수 있다.
따라서:
req.setAttribute("errorMessage", "로그인 실패");
후
dispatcher.forward(req, resp);
하면 JSP에서:
${errorMessage}
를 사용할 수 있다.
resp.sendRedirect("/main");
브라우저에게 새로운 요청을 하도록 한다.
브라우저
↓
Servlet
↓
redirect
↓
브라우저
↓
새로운 요청
↓
다른 Servlet
따라서 기존 Request의 데이터는 다음 요청에서 유지되지 않는다.
HTTP Response Header를 직접 설정한다.
내 SignInServlet에서는:
resp.setHeader(
"Cache-Control",
"no-cache, no-store, must-revalidate"
);
resp.setHeader(
"Pragma",
"no-cache"
);
와 같이 사용했다.
즉:
Servlet
↓
HttpServletResponse
↓
HTTP Response Header 설정
↓
Browser
의 흐름이다.
HTTP Response의 날짜 관련 Header를 설정한다.
내 SignInServlet에서는:
resp.setDateHeader("Expires", 0);
을 사용했다.
로그인 화면의 캐시를 제어하기 위한 설정 중 하나이다.
내 MemoProject에서 실제로 사용했던 Response 메서드는:
| 메서드 | 역할 | 사용 예 |
|---|---|---|
sendRedirect() | 다른 URL로 다시 요청 | 로그인 성공, 회원가입 성공 |
setHeader() | HTTP Header 설정 | 캐시 제어 |
setDateHeader() | 날짜 관련 Header 설정 | Expires 설정 |
이다.
가장 간단하게 정리하면 다음과 같다.
HTTP Request
브라우저 ───────────────────→ Servlet
HttpServletRequest
HTTP Response
브라우저 ←─────────────────── Servlet
HttpServletResponse
클라이언트 → 서버
req.getParameter()
req.getSession()
req.setAttribute()
req.getRequestDispatcher()
주로 요청을 읽거나 데이터를 전달한다.
서버 → 클라이언트
resp.sendRedirect()
resp.setHeader()
resp.setDateHeader()
주로 응답을 설정하거나 다음 요청을 유도한다.
Servlet
↓
HttpServletRequest
├─ getParameter()
├─ getSession()
├─ setAttribute()
└─ getRequestDispatcher()
HttpServletResponse
├─ sendRedirect()
├─ setHeader()
└─ setDateHeader()
Spring과 비교하면:
| Servlet | Spring에서 떠올릴 것 |
|---|---|
req.getParameter() | @RequestParam |
req.setAttribute() | Model.addAttribute() |
req.getSession() | HttpSession |
forward() | View 반환과 비슷한 흐름 |
resp.sendRedirect() | redirect:/... |
resp.setHeader() | HTTP Response Header 설정 |
단, 이것들은 개념적인 대응 관계이지 API가 완전히 동일하다는 의미는 아니다.
결국 HttpServletRequest와 HttpServletResponse는 어렵게 생각할 필요가 없다.
Request는 브라우저가 서버에 보낸 것을 읽고, Response는 서버가 브라우저에게 무엇을 돌려줄지 정한다.
그리고 Servlet에서는 이 두 객체를 직접 다루기 때문에 Spring보다 웹 요청/응답의 동작이 더 눈에 잘 보인다.
브라우저
↓
Request
↓
Servlet
↓
Service
↓
DAO
↓
DB
↓
Servlet
↓
Response
↓
JSP / Browser
이 흐름을 이해하는 것이 JSP/Servlet을 이해하는 첫 번째 단계라고 생각한다.