[필독][기초] / 서블릿 / servlet [part 2]

2016.01.05 14:50language/jsp

서블릿 예제
아래 나오는 모든 예제는 ROOT 애플리케이션에 작성한다.
웹 애플리케이션 작성 실습에서 도큐먼트베이스가 C:/www/myapp 인 애플리케이션을 ROOT 애플리케이션으로 변경했었다.
JSP는 C:/www/myapp 아래에, 자바는 C:/www/myapp/WEB-INF/src 아래 자바 팩키지 이름의 서브디렉토리에 생성한다.
이클립스를 사용하지 않고 에디트플러스와 같은 일반 에디터를 사용한다.

SimpleServlet.java


package example;

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

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

public class SimpleServlet extends HttpServlet {

          @Override
          public void doGet(HttpServletRequest req, HttpServletResponse resp)
                              throws ServletException, IOException {
                    doPost(req,resp);
          }
         
          @Override
          public void doPost(HttpServletRequest req, HttpServletResponse resp)
                              throws ServletException, IOException {
                             
                    resp.setContentType("text/html; charset=UTF-8");
                    PrintWriter out = resp.getWriter();
             
                    out.println("<html>");
                    out.println("<body>");
             
                    //요청한 클라이언트의 IP를 출력
                    out.println("당신의 IP 는 " + req.getRemoteAddr() + "입니다.\n");
                    out.println("</body></html>");
                    out.close();
          }
 
}


SimpleServlet은 서블릿 라이프 사이클 메소드 중 init()과 destroy()는 구현하지 않았다.
이 메소드들은 GenericServlet 에서 이미 구현되어 있고, 또 특별히 오버라이딩할 이유가 없기 때문에 위의 소스에서 보이지 않는 것이다.
 /WEB-INF/web.xml 파일을 열고 web-app 엘리먼트의 자식 엘리먼트로 servlet 엘리먼트와 내용을 아래와 같이 추가한다.


web.xml
/* .. 중간 생략 .. */

    <servlet>
      <servlet-name>SimpleServlet</servlet-name>
      <servlet-class>example.SimpleServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>SimpleServlet</servlet-name>
      <url-pattern>/simple</url-pattern>
    </servlet-mapping>

/* .. 중간 생략 .. */


명령 프롬프트에서 SimpleServlet.java 가 있는 소스 폴더로 이동하여 아래와 같이 컴파일한다.

javac -d C:/www/myapp/WEB-INF/classes ^
-cp "C:/Program Files/Apache Software Foundation/Tomcat 7.0/lib/servlet-api.jar" ^
SimpleServlet.java


SimpleServlet.java 를 컴파일할 때 위와 같은 컴파일 에러가 나온다는 것은 자바 컴파일러가 javax.servlet.http 팩키지를 찾지 못한다는 의미로, javac 의 classpath 옵션의 값으로 servlet-api.jar 파일의 전체경로를 잘못 적었기 때문이다.
classpath 옵션값으로 주는 경로가 중간에 공백이 있다면 "" 으로 묶어주어야 한다.
다른 방법으로는 CLASSPATH 란 환경변수에 servlet-api.jar 의 전체경로를 추가해주면 아래와 같이 classpath 옵션을 사용하지 않고도 컴파일을 할 수 있다.
javac -d C:/www/myapp/WEB-INF/classes SimpleServlet.java (CLASSPATH 환경변수의 값은 반드시 현재 디렉토리를 나타내는 . 를 포함해야 한다.
그래서 CLASSPATH를 설정하면 아래와 같다.
.;C:\Program Files\Apache Software Foundation\Tomcat 7.0\lib\servlet-api.jar 톰캣을 재시작한 후
http://localhost:8989/simple를 방문하여 테스트한다.


SimpleServlet.java 소스설명


public class SimpleServlet extends HttpServlet {


HttpServlet 클래스를 상속받은 서블릿은 public class으로 선언해야 한다.


@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
         
   doPost(req,res);
}

@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
         
   ..생략..
  
}


doGet()과 doPost()메소드는 HttpServlet의 doGet()와 doPost()메소드를 오버라이드 한 메소드이다.
모든 비즈니스 로직이 이 메소드에 존재한다.
HTTP METHOD가 GET으로 요청해오면 doGet() 메소드를 오버라이딩한다.
웹브라우저의 주소창에서 웹서버의 자원을 요청하는 것은 GET방식의 요청이다.
예제에서는 doGet()메소드는 단순히 doPost()메소드를 호출하는 것으로 구현하여 GET이든 POST요청이든 같은 코드가 실행된다.
doGet()과 doPost()메소드는 HttpServletRequest와 HttpServletResponse타입의 파라미터를 가진다.
이 메소드는 예외가 발생할 수 있으므로 throws ServletException, IOExcepiton가 메소드 선언부에 추가되어 있다.


resp.setContentType("text/html; charset=UTF-8");
PrintWriter out = resp.getWriter();


resp.setContentType("text/html; charset=UTF-8");은 응답(HttpServletResponse)의 컨텐츠타입을 셋팅하는 작업을 한다.


웹브라우저에 응답으로 출력될 문서의 MIME타입을 설정하는 것이다.
이 코드는 서블릿에서 단 한번만 사용이 가능하며 PrintWriter를 획득하기 전에 실행되야 한다.
; charset=UTF-8 부분이 빠지면 한글이 깨진다.
PrintWriter의 획득은 HttpServletResponse의 getWriter()을 호출함으로써 이루어진다.


PrintWriter out = resp.getWriter();


out 은 웹브라우저가 목적지인 문자 출력 스트림이다.


out.println("<html>");
out.println("<body>");
//요청한 클라이언트의 IP를 출력
out.println("당신의 IP 는 " + req.getRemoteAddr() + "입니다.\n");


PrintWrtier는 클라이언트로의 응답으로 보내는 스트림에 글을 쓸 수 있게 한다.
PrintWriter의 plintln()메소드안에 문자열을 넣으면 클라이언트의 웹브라우저에 출력된다.
위에서 보듯이 SimpleServlet는 클라이언트에게 HTML을 보내기 위해 PrintWriter의 println()메소드를 사용하고 있다.
req.getRemoteAddr()은 클라이언트의 IP주소값을 반환하는 메소드이다.
이와같이 HttpServeltRequest 는 클라이언트가 보내거나 클라이언트에 관한 정보를 담고 있다.



SimpleServlet 서블릿이 응답을 보내기까지 과정을 살펴보자.
클라이언트가 웹브라우저를 이용해서 서버의 SimpleSerlvet을 요청한다.
서블릿 컨테이너인 톰캣은 SimpleServlet의 +service(ServletRequest req, ServletResponse res) 메소드를 호출하면서 클라이언트의 요청을 캡슐화한 객체(HttpSerlvetRequest 인터페이스 구현체)와 응답을 위한 객체(HttpSerlvetResponse 인터페이스 구현체)를 메소드의 인자로 전달한다.
 +service(ServletRequest req, ServletResponse res) 메소드는 단지 #service(HttpServletRequest req,HttpServletResponse res) 메소드를 호출하도록 구현되어 있다.
 #service(HttpServletRequest req,HttpServletResponse res) 메소드는 HTTP 메소드타입(GET,POST 등)에 따라 doGet() 또는 doPost()메소드를 호출한다.
테스트에서는 웹브라우저의 주소창에서 서블릿 자원을 요청했기 때문에 GET 방식의 요청이다.
따라서 doGet() 메소드가 호출된다.



사용자가 문자열 데이터를 서버측 자원으로 전송하는 방법과 이 데이터를 서버측 자원에서 수신하는 방법
웹 환경에서 동적인 요소라 하면 클라이언트가 보낸 문자열 데이터에 따라 응답을 하는 요소를 말한다.
웹에서 동적인 요소를 만들어야 하는 웹 프로그래머는 클라이언트가 웹 브라우저를 통해서 문자열 데이터를 보내는 방법과 그 데이터를 획득하는 방법을 알아야 한다.
클라이언트 사이드에서 서버 사이드로 문자열 데이터를 전송하기 위해서는 주로 form 엘리먼트와 form의 서브 엘리먼트를 사용한다.
클라이언트가 서버로 전달하는 데이터는 form 엘리먼트의 action 속성의 값으로 지정된 자원으로 전달된다.

 

 

 

참고
http://docs.oracle.com/javaee/7/api/index.html?overview-summary.html
http://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/
http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi
http://commons.apache.org/proper/commons-io/download_io.cgi
http://commons.apache.org/proper/commons-fileupload/using.html
http://www.albumbang.com/board/board_view.jsp?board_name=free&no=292
http://www.docjar.com/docs/api/javax/servlet/GenericServlet.html
http://www.java-school.net/jsp/Servlet

 

 

 

 

도움이 되셨다면 공감을 부탁드립니다. ^^