서블릿에서 클라이언트의 요청을 받고 처리하는 메서드들은 주로 do 접두어가 붙여진 메서드들이 처리를 하는데요. 그 중 doGet과 doPost 메서드는 사용자의 요청이 전송되는 형식에 따라 호출되어 정의된 코드를 실행함으로서 사용자의 요청을 처리하는 주요 메서드입니다.
(자료 출처 : https://velog.io/@zhyun1220/Servlet)
그 중 우선 doPost와 doGet에 대해서 알아볼건데요. 그 전에 우선 Post와 Get에 대해서 알아봐야겠죠?
HTTP 프로토콜의 전송 방식 중에는 크게 Post 방식과 Get 방식이 있는데요. 이 둘은 목적, 캐싱 여부, 길이 제한 등에 따라 차이를 보이는 방식들이랍니다.
클라이언트 측에서 서버에 정보를 요청할 때 주로 사용됩니다. 이 방식은 서버에 요청을 할 때 데이터를 URL 쿼리 문자열로 전송하는데요.
아래의 사진은 사용자가 특정 검색어로 유튜브 검색을 하고 있는 모습입니다.
그리고 요청(엔터)을 하게 되면 서버는 그걸 받아서 정보를 제공하는데요. 이때 나타나는 화면은 다음과 같고, 주소창을 잘 보시면 사용자가 전송한 정보가 주소창에 포함되어 있는 것을 확인할 수 있죠.
이처럼 단순히 서버쪽에서 공통의 정보를 제공하고자 할 때 클라이언트의 요청은 Get 방식을 사용하게 되는 것이죠. 추가로 Get 방식의 특징은 위에서 나열한 것들 외에도 아래의 사항들이 더 있습니다.
클라이언트 측에서 서버에게 정보를 제공할 주로 사용됩니다. 이 방식은 서버에 정보를 전송할 때 URL에 해당 정보들이 포함되지 않고, 캐싱도 되지 않는 방식이므로 로그인, 특정 전자 문서 제출과 같이 주로 개인의 데이터를 서버로 전송할 때 사용됩니다.
아래의 사진은 네이버에서 사용자가 로그인을 할 때의 사진인데요.
일부 정보를 가려서 잘 보이시진 않으시겠지만, 로그인을 하는 순간 주소창을 잘 보시면 Get 방식과 같이 사용자가 입력한 정보가 주소창에 포함되어 있지 않는 듯 보이죠? 하지만 실제로는 사용자가 입력한 정보는 정상적으로 서버에 전송이 된 것입니다.
이처럼 앞서 말씀드린대로 민감한 개인 정보와 같은 데이터를 전송해야 할 때 사용되는 HTTP 프로토콜 전송 방식이 바로 POST 방식인데요. 이러한 POST 방식도 앞서 말씀드린 특징들 말고도 몇 개의 특징이 더 존재합니다.
이러한 POST 방식과 GET 방식은 아래의 두 그림으로도 요약이 가능할 것 같네요!
(자료 출처 : https://whales.tistory.com/120)
여러분들이 Get과 Post 방식에 대해서 아셨다면, 앞서 언급한 doGet, doPost 메서드의 역할도 얼추 아셨을거라 생각합니다. 해당 메서드들은 각각의 방식으로 사용자의 정보가 왔을 때 어떻게 처리를 할 것인지를 정의하는 메서드인데요.
이 메서드를 쓰기 전에, 우선적으로 해주어야 할 것은 앞전의 장에서 살펴본 service 메서드를 이용해 분기를 재정의 해주는 작업이 필요합니다. 즉 실행 될 메서드를 각각 타이밍에 따라 지정해주는 작업이죠.
@Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // req 객체의 getMethod 메서드를 이용해 POST 방식인지, GET 방식인지를 반환받은 뒤 method 변수에 저장 String method = req.getMethod(); // 전송 방식이 GET 이라면 doGost 메서드를 실행 if ("GET".equalsIgnoreCase(method)) { doGet(req, res); } // 전송 방식이 POST 이라면 doPost 메서드를 실행 else if ("POST".equalsIgnoreCase(method)) { doPost(req, res); } // 다른 HTTP 메서드(doHead, doPut, doTrace 등)에 대한 처리는 지금은 제외. else { // get, post방식을 제외한 나머지 메서드 처리 요청은 setStatus로 불가 상수를 세팅한 뒤 사용자에게 불가 항목임을 출력함 res.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); res.getWriter().println("HTTP method not supported."); } }
이제 doPost와 doGet 메서드를 아래와 같이 직접 써주면 되는데, 기본적으로 req 변수를 이용해 사용자가 입력한 정보의 값(Parameter)을 입력 받아 name에 저장하고,
사용자에게 보여질 화면의 콘텐츠 타입 인코딩 방식과 문자 인코딩 방식을 정해준 뒤 화면을 아래의 문자열 HTML 코드와 같이 작성해주면 됩니다.
// doPost 메서드 오버라이딩 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 요청 인코딩 설정 req.setCharacterEncoding("UTF-8"); // 사용자가 요청할 때 보낸 입력 정보(name)을 받아오기 String name = req.getParameter("name"); // 보여질 컨텐츠의 인코딩 세팅 resp.setContentType("text/html;charset=UTF-8"); // 응답 인코딩 세팅 resp.setCharacterEncoding("UTF-8"); // 서블릿에서 사용자에게 데이터 출력을 위해 관례적으로 사용하는 출력 변수를 사용해 코드의 가독성을 높임 PrintWriter out = resp.getWriter(); // 사용자에게 보여질 화면을 출력 out.print("<head><title>Response</title></head>"); out.print("<body>"); out.print("<h1>Hello, " + name + "</h1>"); out.print("<h1>This is from POST Page!</h1>"); out.print("<form action='index.jsp' method='get'>"); out.print("<button type='submit'>Go to Index</button>"); out.print("</form>"); } // doGet 메서드 오버라이딩 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 요청 인코딩 설정 req.setCharacterEncoding("UTF-8"); // 사용자가 요청할 때 보낸 입력 정보(name)을 받아오기 String name = req.getParameter("name"); // 보여질 컨텐츠의 인코딩 세팅 resp.setContentType("text/html;charset=UTF-8"); // 응답 인코딩 세팅 resp.setCharacterEncoding("UTF-8"); // 서블릿에서 사용자에게 데이터 출력을 위해 관례적으로 사용하는 출력 변수를 사용해 코드의 가독성을 높임 PrintWriter out = resp.getWriter(); // 사용자에게 보여질 화면을 출력 out.print("<head><title>Response</title></head>"); out.print("<body>"); out.print("<h1>Hello, " + name + "</h1>"); out.print("<h1>This is from GET Page!</h1>"); out.print("<form action='index.jsp' method='get'>"); out.print("<button type='submit'>Go to Index</button>"); out.print("</form>"); }
그리고 사용자에게 보여줄 JSP 페이지를 다음과 같이 작성해 주는데요. 이 때 해당 페이지에는 각각 전송 방식이 get과 post, 두 가지의 전송 방식에 대한 입력폼을 사용자에게 제공하게 됩니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Hello You!</h1> <form action="page" method="post"> <h2>POST 송신</h2> <label for="name">Name:</label> <input type="text" id="name" name="name"> <button type="submit">Submit</button> </form> <form action="page" method="get"> <h2>GET 송신</h2> <label for="name">Name:</label> <input type="text" id="name" name="name"> <button type="submit">Submit</button> </form> </body> </html>
이때 코드를 자세히 보시면 제가 언급했던 method에는 각각 다른 키워드가 들어가 있는 모습과 함께 name = "name" 속성을 확인하실 수 있으실 겁니다.
이 name 속성은 서버가 값을 가져올 때 어느 DOM 요소, 그러니까 어느 부분으로부터 정보를 가져올지를 정할 때 사용되는 속성으로,
해당 속성에 지정한 값을 이용해 아까 doGet과 doPost 메서드가 req 변수를 이용해 사용자가 입력한 정보를 받아온 부분으로부터 정보를 가져올 수 있는 것이죠.
해당 코드까지 작성을 마친 뒤 이제 JSP 페이지에서 서버를 실행해 주는데요. 그 전에 8080 에러가 뜬다면 여기를 참조하시기를 바랍니다. 물론 자동으로 뜨는 이유는 auto 설정이 디폴트 값으로 선택되어있기 때문이기도 하죠. 그래서 만약 이클립스를 실행할 때마다 해당 8080 에러를 마주하고 싶지 않으시는 분들은auto 설정에서 Never publish 설정으로 바꾸면 됩니다.
그러나 이 경우 저장을 할 때마다 실시간으로 반영되는 화면을 확인하기 힘드니 선택은 여러분들의 몫이랍니다.
아무튼 서버를 실행하면 다음과 같은 창이 뜨는데요.
여기서 Post 송신 쪽에 이름을 적고 버튼을 눌러보겠습니다.
어떠신가요? POST 쪽에 정보를 제출하니 주소창에 정보가 노출되지 않고, doPost에 정의했던 HTML 정보(page)만 출력되죠? 이처럼 service에서 정한 분기, 그러니까 정보 제공 방식(method)에 따라 실행할 메서드가 적절히 호출되는 것을 보실 수 있습니다.
참고로 위의 정보는 개발자 도구(F12)에서 네트워크 탭에 표기되어 있는 헤더의 정보를 참고한 것으로, 헤더는 이후의 장에서 좀 더 자세히 살펴보도록 하죠!
그럼 이 참에 GET 방식도 한 번 해볼까요?
이번에는 주소창에 입력한 정보가 떴죠? 이처럼 POST와 GET 방식은 위의 사진들에서처럼 그 차이점을 알아보았고, 서블릿 컨테이너로 각 전송 방식에 따른 doPost와 doGet 메서드를 간단하게 정의해 보았습니다!