본문 바로가기
Servlet & JSP

Servlet 기초

by kmmguumnn 2018. 6. 29.

Servlet이란, Java 웹 어플리케이션의 구성요소 중, 동적인 처리를 하는 프로그램의 역할을 한다.


즉 Servlet은 

 - WAS에서 동작하는 Java 클래스이다.

 - HttpServlet 클래스를 상속받아야 한다.

 - 웹 페이지를 개발할 때 Servlet과 JSP를 조화롭게 사용하여 최상의 결과를 얻을 수 있다.


자바 웹 애플리케이션의 저장 경로





Servlet 작성 방법



@WebServlet("/LifecycleServlet")
public class LifecycleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    // Constructor: 해당 서블릿 클래스를 메모리에 올림
public LifecycleServlet() {
    // System.out. => console에 출력하는 것
    System.out.println("LifecycleServlet 생성!!");
}


    public void init(ServletConfig config) throws ServletException {
        System.out.println("init 호출!!");
    }


    // 1. WAS 종료 시
    // 2. 코드 수정 후 다시 저장하면, 메모리에 올라가 있던 기존 servlet 객체는 지우고 다시 시작해야 함. => destroy() 호출
    public void destroy() {
        System.out.println("destroy 호출!!");
    }


    // 요청된 객체가 메모리에 이미 있으면, service()만 호출
    // 요청이 왔을 때 응답해야 하는 모든 내용들은 service()에 구현
    protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
        System.out.println("service 호출!!");
    }
}


만약 객체가 이미 메모리에 올라가 있는 상태에서, 소스 파일 일부를 변경하고 저장하게 되면 그 때 destroy()가 호출된다. 기존에 있던 객체는 더 이상 사용할 수 없기 때문이다. 그런 다음 페이지를 다시 요청하면, 생성자 → init() → service()의 순서대로 호출된다.


Servlet의 생명주기를 다시 정리해보자.

  - WAS는 Servlet 요청을 받으면, 먼저 해당 Servlet이 메모리에 있는지 확인한다.

  - 만약 메모리에 없으면, 해당 Servlet 클래스를 메모리에 올린 뒤, init()을 실행한다.

  - service()를 실행한다.


  - WAS가 종료되거나 or 웹 어플리케이션이 새로 갱신됐을 경우, destroy()가 실행된다.

  - 갱신된 것 없이 새로고침만 되는 경우에는 service()만 실행된다.



그럼 service() 메소드에 대해 좀 더 자세히 알아보자.


service(request, response)는 HttpServlet에 템플릿 메소드 패턴으로 이미 구현되어 있다. 만약 service(request, response)를 따로 오버라이드 하지 않은 경우, 부모 클래스, 즉 HttpServlet의 service()가 실행이 되는 것이다.


그럼 HttpServlet의 service(request, response) 메소드는 어떻게 구현되어 있을까? 

service()는 클라이언트의 요청이 GET일 경우는 자신이 가지고 있는 doGet(request, response),
POST일 경우는 자신이 가지고 있는 doPost(request, response)를 호출한다.


정리하면, HttpServlet(부모) 클래스를 상속받아 service() 메소드를 따로 오버라이드 하지 않을 경우, 클라이언트의 요청에 따라 doGet() 혹은 doPost() 메소드가 호출된다. 물론 service() 메소드를 오버라이드 했다면 그 메소드가 호출될 것이다.



이번에는 doGet과 doPost를 오버라이드 해보자.


@WebServlet("/LifecycleServlet")
public class LifecycleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    // Constructor: 해당 서블릿 클래스를 메모리에 올림
public LifecycleServlet() {
    // System.out. => console에 출력하는 것
    System.out.println("LifecycleServlet 생성!!");
}


    public void init(ServletConfig config) throws ServletException {
        System.out.println("init 호출!!");
    }


    // 1. WAS 종료 시
    // 2. 코드 수정 후 다시 저장하면, 메모리에 올라가 있던 기존 servlet 객체는 지우고 다시 시작해야 함. => destroy() 호출
    public void destroy() {
        System.out.println("destroy 호출!!");
    }


    // URL에서 직접 요청이 들어왔을 때
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>form</title></head>");
        out.println("<body>");
        out.println("<form method='post' action='/firstweb/LifecycleServlet'>");
        out.println("name : <input type='text' name='name'><br>");
        out.println("<input type='submit' value='ok'><br>");
        out.println("</form>");
        out.println("</body>");
        out.println("</html>");
        out.close();
    }


    // Submit 버튼을 눌러서 요청했을 때
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        out.println("<h1> hello " + name + "</h1>");
        out.close();
    }


    // 요청된 객체가 메모리에 이미 있으면, service()만 호출
    // 요청이 왔을 때 응답해야 하는 모든 내용들은 service()에 구현
//  protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//      System.out.println("service 호출!!");
//  }


}


URI에 parameter를 직접 입력하거나 링크를 클릭하면 GET 방식이므로 service는 자신의 doGet()을, form 입력 창을 통해서 데이터를 넘길 경우 POST 방식이므로 service는 자신의 doPost()를 호출하게 된다. 어떤 데이터를 전달하느냐에 따라 출력 결과가 달라지므로, 이는 동적인 페이지라고 할 수 있다.





Request, Response 객체 이해하기


이제 HttpServletRequest 객체와 HttpServletResponse 객체에 대해 알아보자.

WAS는 브라우저로부터 Servlet 요청을 받으면,

  - HttpServletRequest 객체를 생성하고, 요청할 때 갖고 있던 정보를 이 객체에 저장한다.

  - 브라우저에게 응답을 보낼 때 사용하기 위하여, HttpServletResponse 객체를 생성한다.

  - 생성된 HttpServletRequest, HttpServletResponse 객체를 Servlet에게 전달한다.


HttpServletRequest

  - Http 프로토콜의 request 정보를 Servlet에게 전달하기 위한 목적으로 사용.

  - 헤더 정보, 파라미터, 쿠키, URI, URL 등의 정보를 읽어들이는 메소드를 갖고 있다.

  - Body의 Stream을 읽어들이는 메소드를 갖고 있다.


HttpServletResponse

  - WAS는 어떤 클라이언트가 요청을 보냈는지 알고 있고, 해당 클라이언트에게 응답을 보내기 위한 HttpServleResponse 객체를 생성하여 Servlet에게 전달.

  - Servlet은 해당 객체를 이용하여 content type, 응답코드, 응답 메시지 등을 전송.





아래는 HttpServletRequest에서 헤더 정보를 읽어 들이는 메소드를 사용한 샘플 코드이다.

@WebServlet("/header")
public class HeaderServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public HeaderServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>form</title></head>");
		out.println("<body>");

		Enumeration<String> headerNames = request.getHeaderNames();
		while(headerNames.hasMoreElements()) {
			String headerName = headerNames.nextElement();
			String headerValue = request.getHeader(headerName);
			out.println(headerName + " : " + headerValue + " <br> ");
		}		
		
		out.println("</body>");
		out.println("</html>");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}



아래는 HttpServletRequest에서 파라미터를 읽어 들이는 메소드를 사용한 샘플 코드이다.

@WebServlet("/param")
public class ParameterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ParameterServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>form</title></head>");
		out.println("<body>");

		String name = request.getParameter("name");
		String age = request.getParameter("age");
		
		out.println("name : " + name + "<br>");
		out.println("age : " +age + "<br>");
		
		out.println("</body>");
		out.println("</html>");
	}

}



마지막으로, 그 외의 다양한 요청 정보들을 출력하는 샘플 코드이다.

@WebServlet("/info")
public class InfoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public InfoServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>info</title></head>");
		out.println("<body>");

		String uri = request.getRequestURI();
		StringBuffer url = request.getRequestURL();
		String contentPath = request.getContextPath();
		String remoteAddr = request.getRemoteAddr();
		
		
		out.println("uri : " + uri + "<br>");
		out.println("url : " + url + "<br>");
		out.println("contentPath : " + contentPath + "<br>");
		out.println("remoteAddr : " + remoteAddr + "<br>");
		
		out.println("</body>");
		out.println("</html>");
	}


}








참고자료


HTTP Headers on MDN





'Servlet & JSP' 카테고리의 다른 글

Servlet & JSP의 4가지 Scope  (0) 2018.07.01
Forward, 그리고 Servlet & JSP의 연동  (0) 2018.06.30
Redirect  (0) 2018.06.29
JSP 기초  (0) 2018.06.29
미들웨어 / 웹서버 / WAS  (0) 2018.05.30

댓글