본문 바로가기

WEB

[WEB] HTTP요청과 HttpServlet

HTTP 요청과 service()

서블릿은 클라이언트에게 요청이 들어오면 service() 메서드를 호출하여 처리한다. 그렇다면 http 요청은 service() 메서드로 어떻게 처리할 수 있을까? 일단 http 요청은 대표적으로 GET 요청과 POST 요청이 있다. 일단 이 두 요청을 분류해서 해결할 필요가 있다. 

public void service(ServletRequest req, ServletResponse res) {
	
    private boolean isGet;
    pirvate boolean isPost;
    
    // http 요청을 파싱하여 get 요청 / post 요청 여부 확인
    
    if (isGet) { doGet(...) }
    if (isPost) { doPost(...) }
}

public void doGet(...) { /* GET 요청 처리 */ }
public void doPost(...) { /* POST 요청 처리 */ }

 대충 위의 코드처럼 짠다면 GET 요청과 POST 요청을 분류하여 처리할 수 있을 것 같다. 결국 http 요청이 들어오면 service() 메서드가 호출되고 service() 메서드는 요청을 해석하여 GET 요청과 POST 요청을 분리해 각자의 메서드를 호출한다. 실제로 자바는 다음과 같은 역할을 하는 서블릿을 제공하고 있는데 그것이 바로 HttpServlet이다.

 

HttpServlet

HttpServlet 은 GenericServlet을 상속받은 객체이다. HttpServlet의 service() 메서드는 http 요청이 들어오면 자동으로 get요청과 post 요청을 분리하여 get 요청의 경우 doGet()을 호출하고 post 요청의 경우 doPost()을 호출한다. 즉, HttpServlet을 상속 받은 서블릿은 doGet()과 doPost() 만을 재정의하면 http 요청을 손쉽게 처리할 수 있다.

 

ServletRequest와 ServletResponse

서버와 클라이언트는 서로 통신을 하면서 요청과 응답에 필요한 다양한 데이터를 주고 받는다. 이때 이러한 데이터를 다루기 위해 필요한 객체가 ServletRequestServletResponse이다. 참고로 HttpServelt에서는 HttpServletRequest와 HttpServletResponse를 사용한다.

 

먼저, 클라이언트가 요청 정보를 다룰때는 ServletRequest를 사용한다. 특히, GET 요청이나 POST 요청과 함께 전달된 데이터를 꺼낼때는 getParameter() 메서드를 사용하면 된다.

// GET요청 : http://localhost:9999/exmaple/ex?a=20&b=10 

request.getParameter("a");	// a 값 꺼내기
request.getParameter("b");	// b 값 꺼내기

 

클라이언트에게 다시 응답을 보낼때 사용되는 객체는 ServeltResponse이다. 특히, 출력할 데이터의 형식과 인코딩 방식 지정하고, 출력 스트림을 통해 출력을 한다.

// 화면에 '안녕하세요' 출력하기

response.setContentType("text/plain");	// 출력형식은 text

response.setCharacterEncoding("UTF-8");	// 유니코드를 UTF-8로 변환

 

 계산기 만들기

Request와 Response 그리고 doGet, doPost가 어떻게 쓰이는지를 계산기 예제를 통해 알아보자.

입력창에 숫자를 입력하고 연산기호를 선택하면 결과를 수식과 함께 알려준다.

CalculationServlet.java (계산 수식 입력)

package calc.servlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/calc/input")
public class CalculationServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
        	// 화면출력
		out.print("<html>");
		out.print("<head><title>계산기</title></head>");
		out.print("<body>");
		out.print("<form action='result' method='get'>");
		out.print("<input type='text' name='v1'>");
		out.print("<select name='op'>");
		out.print("<option value='+'>+</option>");
		out.print("<option value='-'>-</option>");
		out.print("<option value='*'>*</option>");
		out.print("<option value='/'>/</option>");
		out.print("</select>");
		out.print("<input type='text' name='v2'>");
		out.print("<input type='submit' value='='>");
	}

}

다음은 계산을 위해 숫자를 입력하고 연산기호를 선택하여 계산을 요청하는 서블릿이다. 클라이언트는 URL 입력을 통해 해당 페이지에 접속하므로 GET 요청을 통해 접속한다고 할 수 있다. 그렇기 때문에 화면을 출력 하는 기능은 doGet에 구현해야 한다. 또한 숫자와 연산기호를 입력받고 GET 요청을 통해 /calc/result 경로로 계산을 요청하므로 form의 method 속성은 get으로 설정해주었다.

 

CalculationResultServlet.java (결과 출력)

package calc.servlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/calc/result")
public class CalculationResultServlet extends HttpServlet {

	private static final long serialVersionUID = 2L;
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
		
		int v1 = Integer.parseInt(request.getParameter("v1"));
		int v2 = Integer.parseInt(request.getParameter("v2"));
		String op = request.getParameter("op");
		
		String printResult = "";

		switch (op) {
			case "+":
				printResult = v1 + " + " + v2 + " = " + (v1+v2);
				break;
			case "-":
				printResult = v1 + " - " + v2 + " = " + (v1-v2);
				break;
			case "*": 
				printResult = v1 + " * " + v2 + " = " + (v1*v2);
				break;
			case "/":
				if (v2 == 0) { printResult = "잘못된 수식입니다"; }
				else { printResult = v1 + " * " + v2 + " = " + (v1/v2); }
				break;
			default:
				printResult = "잘못된 수식입니다";
		}
		
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		out.print("<html>");
		out.print("<head><title>결과</title></head>");
		out.print("<body>" + printResult + "<br>");
		out.print("<form action='input' method='get'>");
		out.print("<input type='submit' value='돌아가기'>");
		out.print("</form></body>");
		out.print("</html>");
	}

}

위 코드는 계산 결과를 출력하는 서블릿이다. 연산자와 숫자를 입력받은 서블릿이 해당 서블릿에 GET 요청을 보내므로 요청에 대한 응답 코드는 doGet을 통해 구현해야한다. requset.getParameter 메서드를 통해 클라이언트가 보낸 숫자와 연산기호를 받는다. 그 후 받은 데이터를 이용해 출력할 문자열을 만든 후 출력한다. 그리고 돌아가기 버튼을 만들어 GET 요청을 통해 입력 페이지로 돌아갈 수 있게 하였다.

 

위 예제를 POST 요청을 통해서도 만들수 있다. Calculation 서블릿의 form 태그의 method 속성을 'post'로 설정한 후 CaculationResult 서블릿의 doPost 메서드를 오버라이딩 하면 POST 요청에 의해 계산기 작동되는 것을 확인할 수 있다.