본문 바로가기
Web Programing!/JAVA / JSP

[JSP] Servlet이란?

by 어설픈봉봉이 2011. 7. 31.
반응형
SMALL



Servlet이란?

Servlet은 Request/Response 기반의 서버 프로그램 개발 기술로서

주로 Web 서버용 응용 프로그램 개발에 사용되는 기술이다.

Web 서버의 기능을 확장하여 특정 기능의 미들웨어를 구현하고자 하는 경우등에 할용할 수 있다.

 

             Server + Applet = Servlet

 

Servlet의 특징은

- main() 메소드를 구현하지 않는다.

- Servlet, GenerocServlet, HttpServlet 중 하나를 상속하여 구현한다.

- init(), service(), destroy() 등의 메소드들이 정해진 순서로 호출된다.(Callback 방식)

- Application 과 달리 단독으로 수행될 수 없다.


Servlet 디렉토리

Servlet이 공식적으로 존재하게 되는 디렉토리로서 Web 서버(Servlet 엔진)에 따라서 설정하는 방법에 차이가 있지만, 설정된 후에는 모든 Servlet 프로그램의 클래스들이 이 디렉토리에 존재해야만 Web 서버가 인식하고 호출하게 된다.
이 디렉토리를 Servlet 디렉토리라고 한다.

 

http://서버주소:포트번호/servlet/Servlet클래스명

 

/servlet/Servlet클래스명은 서버의 정의된 Web Application 디렉토리의 Servlet 디렉토리인 WEB-INF/classes에서 Servlet클래스명에 해당되는 Servlet 클래스가 인식되어 수행된다.

 

각 Web Application마다 Servlet 디렉토리는 하나씩 존재하게 되며 Web Application의 path명이 /xxx 인 경우에는 Servlet 요청시 /xxx 를 URI의 맨 앞에 붙여 준다.

 

http://서버주소:포트번호/xxx/servlet/Servlet클래스명

 

Servlet의 수행 흐름

1. Client에서 Servlet의 호출을 요청한다.

2. 요청을 받은 웹서버(Servlet 엔진)는 요청된 Servlet의 인스턴스가 이미생성되어 있는지 점검한다.

3. 해당 Servlet의 인스턴스가 생성되어 있지 않은 경우, Servlet 클래스를 메모리에 로딩하고

   인스턴스를 생성한다.

4. 해당 Servlet의 인스턴스가 생성되어 있는 경우, service() 메소드를 수행하고 결과를 웹서버에게 돌려준다.

5. 웹서버는 Client에게 결과를 리턴한다.

 

Sun은 Servlet을 자바에 대한 첫번째 확장이라고 표현했다. 즉 Servlet이 공식적으로 Sun사에 의해 지원되며 자바 언어의 일부분이긴 하지만, Core Java API의 일부분은 아니므로 Servlet 클래스는 모든 JVM에 기본적으로 포함되어 있지는 않다는 말입니다.

 

따라서 서버에서 Servlet을 실행하기 위해서는 Sun에서 제공하는 Servlet Package가 필요합니다.

 

javax.servlet Package의 구조

1. 인터페이스

1) RequestDispatcher

클라이언트로부터 나오는 요청(Request)을 받아들이는 객체를 정의하며,

그 객체들을 서버상에 존재하는 자원(servlet, HTML 파일, JSP 파일)에 보내는 역할을 한다.

 

2) Servlet

모든 Servlet들이 구현해야 하는 메소드들을 정의한다.

 

3) ServletConfig

Servlet 컨테이너에 의해 사용되며, Servlet의 초기화 중에 정보를 servlet에 전달하는데 사용한다.

 

4) ServletContext

Servlet이 해당 Servlet 컨테이너와 통신하는데 사용하는 메소드들을 정의하는 것으로, 여기에는 파일의 MIME 형식을 받아오며, 요청(Request)을 서버상의 자원들에게 전해주며(dispatch), 로그 파일에 기록하는 것들이 있다.

 

5) ServletRequest

클라이언트의 요청(Request) 정보를 Servlet에 전달하는 객체를 정의한다.

 

6) ServletResponse

클라이언트에 응답(Response)을 보내는데 있어 Servlet을 보조해주는 역할을 하는 객체를 정의한다.

 

7) SingleThreadModel

Servlet이 한번에 오직 하나의 요청(Request)을 처리하도록 한다.

 

2. 클래스

1) GenericServlet

일반적이고, 프로토콜 돌립적인 Servlet을 정의한다.

 

2) ServletInputStream

클라이언트로부터의 바이너리 데이터를 읽기 위한 input stream을 제공하는데, 한번에 한라인씩 데이터를 읽기 위한 readLine 메소드를 포함한다.

 

3) ServletOutputStream

클라이언트에 바이너리 데이터를 보내기 위한 output stream을 제공한다.

 

3. Exception

1) ServletException

일반적인 Servlet Exception을 정의한다.

 

2) UnavailableException

해당 Servlet이 영구적, 혹은 잠시 서비스하지 못한다는 것을 가리키는 Exception을 정의한다.

 

 

javax.servlet.http Package의 구조

1. 인터페이스

1) HttpServletRequest

ServletRequest 인터페이스를 상속받은 것으로 HTTP servlet에 요청 정보를 제공한다.

 

2) HttpServletResponse

ServletResponse 인터페이스를 상속받은 것으로 응답을 보내는데 있어 HTTP 프로토콜에만 존재하는 특정 기능을 제공한다.

 

3) HttpSession

여러 페이지에 걸쳐 사용자를 구별하거나, 그 유저에 대한 정보를 저장하기 위한 방법을 제시해 준다.

 

2. Class

1) Cookie

쿠키를 생성하는데 사용되는데 쿠키는 servlet에 의해서 웹 브라우저에 보내져, 브라우져에 의해 저장되며, 차후에 서버에 다시 전해지는 그리 크지 않은 정보를 의미한다.

 

2) HttpServlet

추상클래스를 제공하는데, 이는 웹사이트에 맞는 HTTP servlet을 생성하기 위해 특정 클래스(servlet)가 상속받게 된다.

 

예제 학습

File name : HelloWorld.java

// HelloWorld 서블릿
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

    // 이미 생성된 servlet에, 클라이언트의 요청(request)이
    // 들어오면 Servlet 컨테이너는 servlet의  service
    // 메소드를 호출하고, HTTP get 방식의 요청(requet)일때,
    // service 메소드는 doGet을 호출한다.
    public void doGet (HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        // 응답(response)의 콘텐츠 형식을 text/html로 맞춘다.
        response.setContentType("text/html");

        // 텍스트 전송시 Writer 객체를 얻어서 프린트한다. 
        PrintWriter out = response.getWriter();
 
        out.println("<html>");
        out.println("<body>");
        out.println("<head>");
        out.println("<title>Hello World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");

 

        //응답(response)을 보낸후 Writer 을 닫는다. 
        out.close();
    }
}

코드에서 보듯 HelloWorld는 HttpServlet 클래스를 상속받으며, HttpServlet 클래스는 Servlet 인터페이스에서 상속된 것이다.

 

HelloWorld는 HttpServlet 클래스에 있는 doGet 메소드를 override한다.

doGet 메소드는 HTTP 요청의 기본 방식인 GET 요청을 처리할 때 호출되며, 단순한 HTML 페이지를 클라이언트에 전송하게 된다.

 

doGet 메소드는 HttpServletRequest 객체에 담겨 있는 사용자의 요청에 따른 응답을 HttpServletResponse 객체에 담아서 웹서버로 전해준다.

위의 예제코드에서는 텍스트 데이터만을 요청한 경우이므로, 응답은 HttpServletResponse 객체로부터 얻어지는 Writer 객체를 사용하여 전해진다.

 

만약 요청 데이터로부터 넘어온 값들을 DB에 저장해야 한다면 위의 doGet 메소드안에 해당하는 자바 코드를 작성해서 넣어 주면 되는 것이다.

 

아주 단순한 구조를 가지고 있는 것처럼 보이지만 실제 Servlet은 위의 기본구조를 지키면서

필요한 코드를 doGet 또는 doPost 메소드 내부에 구현하기만 하면 된다.

물론 Query String에 담겨 오는 요청 정보라든지, 다른 Servlet이나 HTML과의 자료교환 등등의

기능이 필요하다면 javax.servlet이나, javax.servlet.http package에 담겨 있는 적당한

class들이 가지고 있는 API를 이용하면 된다.

 

ServletContext 개요

웹 어플리케이션들이 공통적으로 관리하고 참조할 수 있는 정보를 공유하기 위해서 Servlet은 ServletContext란 것을 제공한다. 이 ServletContext를 사용하여 servlet간에 자원을 공유하게 됨으로써 한정된 서버자원을 절약하는 것은 물론이고, servlet들이 하나의 어플리케이션으로 통합할 수 있도록 한다. 즉, servlet간에 주고 받아야 할 정보들이 ServletContext를 통해서 공유됨으로서 서로 쉽게 주고 받을 수 있게 되는 것이다.

 

이렇게 servlet간에 공유정보를 주고받기 위해선 javax.servlet.ServletContext란 인터페이스내의

setAttribute, getAttribute, removeAttribute란 메소드를 이용하면 된다.

 

setAttribute(오브젝트명, Object) 주어진 이름의 Object를 각 Servlet이 공유할 수 있도록 저장한다.

getAttribute(오브젝트명)              공유 중인 해당 오브젝트명의 Object를 얻어 온다.

removeAttribute(오브젝트명)        해당 오브젝트명의 Object를 메모리에서 삭제한다.

 

위의 메소드를 사용할 때 주위할 점은 setAttribute를 통해 공유오브젝트를 저장할 경우엔 반드시 java Object형태만 저장이 가능하다는 것이다.

다시 말해 int, long과 같은 형태의 값들은 반드시 Integer, Long과 같은 형태의 Object로 변환한 후에 저장해야 한다는 것이다.

 

getAttribute 메소드의 경우 리턴값이 Object이므로 원하는 형테로 Class Casting한 후에 사용해야 한다. 즉 setAttribute 메소드를 통해 Integer 형태의 Object를 저장했다면, (Integer)getAttribute("XXX") 와 같이 Casting해야만 한다는 것이다.

 

Servlet의 실행 과정

1. Servlet 컨테이너(엔진)는 스레드풀을 생성하여 미리 설정해 놓은 갯수만큼의 스레드를 사용할 수 있도록 준비한다.

 

2. Servlet 컨테이너는 Servlet의 인스턴스를 생성한다. 즉 Servlet을 객체화 하여 서버의 메모리에 올려두는 것이다.

 

3. 사용자가 서버에 보낸 요청에 따라, 각 Servlet의 인스턴스들은 service() 메소드를 호출한다.

   이때 만약 해당 Servlet이 GenericServlet이 아니고 HttpServlet 클래스를 상속받았다면 override된 service 메소드가 doGet() 또는 doPost() 메소드를 다시 호출한다.

 

4. 요청에 대한 처리가 끝나면 사용자에게 응담을 보낸다.

 

5. Servlet 컨테이너가 셧다운을 시작하게 되면 현재 실행중인 스레드가 종료되기를 기다린 후, 스레드풀을 종료시키고, Servlet의 destroy() 메소드를 수행한 후 Servlet을 종료하고, 컨테이너를 최종적으로 셧다운 한다.  

 

예제학습

//Servlet의 수행 흐름 점검예제

//파일명 : FlowServlet.java

import javax.servlet.*;
import javax.servlet.http.*;

 

public class FlowServlet extends HttpServlet {

    public void init(ServletConfig sc) {
        System.out.println("init() 가 호출되었습니다.");
    }

 

    public void service(ServletRequest reg, ServletResponse res) {
        System.out.println("service() 가 호출되었습니다.");
    }

 

    public void destroy() {
        System.out.println("destroy() 가 호출되었습니다.");
    }
}

 

기본 Method

1. init()

Servlet 컨테이너가 Servlet을 로드할 때, Servlet 컨테이너는 우선 해당 Servlet의 init() 메소드를

호출하게 된다.

init() 메소드는 Servlet이 로드될 때 한번만 수행되며, Servlet 컨테이너가 Servlet을 다시 로드하지 않는 한 다시 수행되지 않는다. 이렇게 Servlet의 init() 메소드의 수행이 끝나야만 해당 Servlet은 service() 메소드을 통해 클라이언트들의 요청을 받아 처리 할 수 있다.

 

2. doGet()

HttpServlet 클래스를 상속받은 Servlet에서 HTTP의 GET요청을 처리하는 것은 doGet() 메소드를 override하여 구현한다.

doGet() 메소드는 파라메터로 HttpRequest 객체와 HttpResponse 객체를 받는다.

HttpResponse 객체에서 얻은 PrintWriter를 통해서 결과 화면을 구성하게 된다.

 

3. doPost()

HttpServlet 클래스를 상속받은 Servlet에서 HTTP의 POST요청을 처리하는 것은 doPost() 메소드를 override하여 구현한다.

doPost() 메소드는 doGet()과 마찬가지로 HttpRequest 객체와 HttpResponse 객체를 파라메터로 받는다.

 

4. destroy()

Servlet은 시스템 관리자 같은 사용자의 요청에 따라 소멸되기 전까지는 계속 동작한다.

서버, 즉 Servlet 컨테이너가 Servlet을 소멸시킬 때, 서버는 Servlet의 destroy() 메소드를 수행시킨다. 이 메소드는 한번만 실행된다.

비록 init() 메소드를 override하는 대부분의 Servlet이 초기화 과정을 되돌리기 위해서 destroy() 메소드를 override하고 있지만, 이는 반드시 필요한 것은 아니다.

 

5. getServletInfo()

몇몇 어플리케이션에서는 Servlet으로부터 상세정보를 받아 그것을 보여주기도 한다.

servlet description은 Servlet의 목적, 작성자, 버전번호, 또는 Servlet 작성자가 중요하다고 생각하는 것들을 설명할 수 있는 문자열이다.

바로 이런한 정보를 반환하는 메소드가 getServletInfo() 메소드이다.

 

Servlet 프로그래밍 관려 추상 자료형의 상속

1. Servlet 수행시 호출되는 메소들들인 init(), service(), destroy()등의 메소드를 모두 override하여 기능을 구현하고자 하는 경우에는 Servlet 인터페이스를 상속한다.

Servlet 인터페이스는 Servlet 프로그래밍 시 반드시 구현해야 하는 인터페이스로, init(), service(), destroy() 메소드 등을 정의하고 있다. 이 인터페이스는 Servlet 프로그램의 생명주기와 매칭된다.

 

2. service() 메소드를 override하여 미들웨어등의 서버 기능을 구현하고자 하는 경우 또는 요청 방식에 관계없는 Servlet 구현시 GenericServlet 클래스를 상속한다.

GenericServlet 클래스는 Servlet 인터페이스를 상속하여 네트워크 통신에 적합한 새로운 클래스로 만든 것으로 클라이언트와 네트워크 통신을 할 때 필요한 인터페이스들을 구현한 것이다. GenericServlet을 HTTP 프로토콜에 맞게 확장시킨 것이 HttpServlet이다.

 

3. Web 클라이언트로부터의 요구 방식에 따라 doGet(), doPost()만을 override하고자 하는 경우에는 HttpServlet 클래스를 상속한다.

HttpServlet 클래스는 HTTP 프로토콜 기반으로 클라이언트로부터 전달된 요청을 받아서 처리하고, 그 결과를 다시 클라이언트에게 되돌려 주는 클래스이다.

Web기반의 Servlet 프로그램 개발은 HttpServlet을 상속하여 구현한다.

 

브라우저에서 URL 문자열을 이용하여 Web 서버에 Servlet 수행을 요청하면 Web 서버는 해당 Servlet 프로그램을 수행시키고 그 결과를 브라우저로 응답하게 된다.

 

Hello Servlet

특별한 경우가 아니라면 HttpServlet을 상속한다. Servlet 수행에 대한 디폴트 요청 방식은 Get 방식이므로 간단하게 doGet() 메소드만을 overrider하여 구현한다.

브라우저로 결과를 반환할 경우에는 먼저 setContextType()이라는 메소드를 활용하여 반환되는 정보의 형식과 문자셋등을 지정한다. 그리고, 결과를 모두 전송한 후에는 반드시 close() 메소드를 호출해 주어야 한다.

 

예제학습

//브라우저로 "Hello?"를 출력하는 Servlet

//파일명 : HelloServlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

 

public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        res.setContentType("text/html");
        PrintWriter out = res.getWriter();
        out.println("<HTML><HEAD><TITLE>First Example</TITLE>");
        out.println("</HEAD><BODY><H1>Hello?</H1>");
        out.println("</BODY></HTML>");
        out.close();
    }
}

 

예제학습

//브라우저로 "안녕?"를 출력하는 Servlet

//파일명 : HanHelloServlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

 

public class HanHelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
                        throws ServletException, IOException {
        //브라우저가 한글 코드셋으로 설정되어 있지 않아도 전송된 코드들을

        //KSC5601로 설정하여 처리하도록 MIME Type과 codeset을 설정

        res.setContentType("text/html; charset=KSC5601");
        PrintWriter out = res.getWriter();
        out.println("<HTML><HEAD><TITLE>첫번째 예제</TITLE>");
        out.println("</HEAD><BODY><H1>안녕?</H1>");
        out.println("</BODY></HTML>");
        out.close();
    }
}

 

브라우저에서 적절한 URL 문자열을 이용하여 Web 서버에 Servlet 수행을 요청할 때 일정한 형식의 요청 문자열이 즉, 브라우저에 대한 정보, 클라이언트 시스템에 대한 정보, Query 문자열등 다양한 정보가 서버로 전달된다.

이 정보를 이용하여 요청을 보내온 클라이언트에 대한 다양한 정보를 추출하여 처리할 수 있다.

 

요청(Request) 정보 추출

Web 서버(Servlet 엔진)는 브라우저에서 전송된 정보에 자신에 대한 정보, 즉 Web 서버에 대한 정보를 포함하여 수행될 Servlet 프로그램에게 전달하게 된다.

Servlet 엔진을 통해 인스턴스화된 HttpServletRequest 인터페이스의 다양한 메소드의 호출을 통해 필요한 정보를 얻어내어 기능을 처리할 수 있다.

 

예제학습

//HTTP 상에서의 클라이언트로부터의 Request 정보를 출력하는 기능

//파일명 : InfoServlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

 

public class InfoServlet extends HttpServlet {
 public void doGet (HttpServletRequest req, HttpServletResponse res) 
  throws ServletException, IOException {
   PrintWriter out;
   res.setContentType("text/html;charset=KSC5601");
   out = res.getWriter ();
   out.println("<html>");
   out.println("<head><title>Request 정보 출력 Servlet</title></head>");
   out.println("<body>");
   out.println("<h1>Request information:</h1>");
   out.println("<pre>");
   print(out, "Request method", req.getMethod());
   print(out, "Request URI", req.getRequestURI());
   print(out, "Request protocol", req.getProtocol());
   print(out, "Servlet path", req.getServletPath());
   print(out, "Path info", req.getPat hInfo());
   print(out, "Path translated", req.getPathTranslated());
   print(out, "Query string", req.getQueryString());
   print(out, "Content length", req.getContentLength());
   print(out, "Content type", req.getContentType());
   print(out, "Server name", req.getServerName());
   print(out, "Server port", req.getServerPort());
   print(out, "Remote address", req.getRemoteAddr());
   print(out, "Remote host", req.getRemoteHost());
   out.println("</pre>");
   out.println("</body></html>");
     }
     private void print (PrintWriter out, String name, String value)  {
   out.print(" " + name + ": ");
   out.println(value == null ? "&lt;none&gt;" : value);
     }
     priva te void print (PrintWriter out, String name, int value)  {
   out.print(" " + name + ": ");
   if (value == -1) {
    out.println("&lt;none&gt;");
   } else {
    out.println(value);
   }
  }
 }

 

예제학습

//클라이언트에서 Request-Header 정보를 출력하는 Servlet

//파일명 : HeaderServlet.java

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

 

public class HeaderServlet extends HttpServlet {
 public void doGet (HttpServletRequest req, HttpServletResponse res)
     throws ServletException, IOException {
  PrintWriter out;
  res.setContentType("text/html");
  out = res.getWriter ();
  out.println("<html>");
  out.println("<head><title>Request 정보 출력 Servlet</title></head>");
  out.println("<body>");
  Enumeration em = req.getHeaderNames();
  while (em.hasMoreElements()){
                    String s = (String)em.nextElement();
                    out.println(s +" : ");
                 & nbsp;  out.println(req.getHeader(s)+"<br>");
  }
  out.println("</body>");
  out.println("</html>");
         out.close();
 }
}

 

동일한 Servlet 프로그램에 대한 수행 요청이 동시에 여러 개가 전송되었을 때는 수행 요청마다 스레드를 생성하여 동일한 Servlet 객체의 해당 메소드를 호출하게 된다.

즉 여러 스레드에 의해 요청된 Servlet 객체가 공유되므로 멤버 변수가 공유되는 결과가 된다.

이 때 동시에 수행되어 멤버 변수가 공유되므로 리소스의 충돌이 예상되거나, 일관성 유지를 할 수 없는 경우 Thread-Safe Servlet을 개발하여야 한다.

 

Thread-Safe Servlet이란 클라이언트에서 Servlet이 동시에 요청되었을 때 하나의 객체 상에서 멀티 스레드가 아니고 서로 다른 객체상에서의 멀티 스레드를 처리하여 멤버 변수가 공유되지 않도록 하는 기술이다.

즉 하나의 Servlet 객체에서 단지 하나의 스레드만 수행되도록 하는 방식이다.

 

이는 SingleThreadModel이라는 인터페이스를 상속받기만 하면 되며, 이 추상자료형은 인터페이스로서 제시하고 있는 abstract 메소드가 없다. 단지 이 인터페리스를 상속받으므로해서 "이 Servlet은 Thread-Safe Servlet이다"라는 것을 알리는 용도로만 쓰인다.

 

public class TestServlet extends HttpServlet implements SingleThreadModel


브라우저에서 사용자들이 입력한 정보를 Web 서버에 전송할 수 있으며, 이 문자열을 Query 문자열이라고 한다. Web 서버는 전달되는 Query 문자열을 요청된 Servlet 프로그램에게 전달하여 브라우저와 Servlet 프로그램간에 상호 작용 기능을 수행하도록 한다.

 

Query 문자열 전송 방식

Query 문자열을 서버에 전달하는 방식은 GET 방식과 POST 방식이 있다.

GET방식은 Query 문자열을 호출하는 Servlet 프로그램의 URL 뒤에 ? 기호와 함께 추가하여 Request Header에 전달하는 방식이며, POST방식은 Request Body에 넣어서 서버로 전송하는 방식이다.

 

브라우저 사용자가 입력한 정보는 서버로 입력된 그대로 전달되는 것이 아니며 이미 정의된 방식으로 encoding되어 전달된다. encoding되어 전달된 Query 문자열의 decoding은 Web 서버가 하는 것이 아니라 Servlet 프로그램에서 처리하게 된다.

Servlet API 중 Query의 내용을 추출하는 기능의 메소드로 String getParameter(String) 또는

String[] getParameterValues(String name)가 활용된다.

 

Query 문자열은 name=value라고 하는 일정한 형식으로 전달되므로 name을 활요하여 value값을 얻어낼 수 있다.

"name"을 매개변수로 지정하여 "value"값을 추출하는 기능의 메소드는 HttpServletRequest에서 제공되는 다음의 메소드를 활용한다.

 

String getParameter(String name)

String[] getParameterValues(Strinf name)

 

예제학습

//브라우저로부터의 Query 정보를 GET 방식으로 전달받아 출력하는 기능

//파일명 : InputServletGet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


public class InputServletGet extends HttpServlet {
    public void doGet (HttpServletRequest req, HttpServletResponse res)
          throws ServletException, IOException {
        res.setContentType("text/html; charset=KSC5601");
        PrintWriter out;
        req.setCharacterEncoding("EUC-KR");
        String name = req.getParameter("stname");
        String addr = req.getParameter("staddr");
        String item[] = req.getParameterValues("stitem");
        out = res.getWriter();     
        out.println("<html><body><h1>입력 결과< ;/h1><hr>");
        out.println("이름은 "+ name +"이고 주소는 " + addr + " 입니다.");
        out.println("이름의 길이는 " + name.length());
        if (item == null)
            out.println("<br>선택하신 상품이 없네요...");
       else {
            out.println("<br>선택하신 상품은<br>");
            for (int i=0;i < item.length; i++)
                out.print (item[i]+" ");  
            out.println("<br>입니다");
        }
        out.println("</bo dy></html>");
        out.close();
    }
}


Session Tracking이란 각 클라이언트마다 이전 연결의 최종 상태를 개별적으로 유지하는 것으로서 사용자가 여러번 정보를 전달하고 그 정보가 계속적으로 유지되어야 하는 경우 활용될 수 있는 기술이다.

 

Session Tracking 관련 API

Session Tracking은 내부적으로 Cookie 기술을 활용한다.

그러나 일반적인 Cookie와는 약간의 차이점을 가지고 있다.

- Session Tracking의 최대 유효시간은 현재 브라우저가 종료될 때까지이다.

- 클라이언트에 저장되는 정보는 유지시키고자 하는 정보가 아니라 정보에 대한 SessionID가 된다. 즉, 정보는 서버에 저장되고 클라이언트에는 정보에 대한 ID만을 저장하여 관리하는 기술이다.

- 유지시킬 정보를 등록(setAttribute())하고 추출(getAttribute())하는 기능의 메소드를 제공한다.

 

    HttpSession 객체 추출

 

    HttpSession session = request.getSession(false);

 

    클라이언트에 설정된 Session정보를 추출한다. 설정된 SessionID가 존재하면 이 ID에 해당되는

    HttpSession객체를 리턴한다. 없으면 null을 리턴한다.

 

    HttpSession 객체 추출/설정

 

    HttpSession session = request.getSession(true);

 

    클라이언트에 설정된 Session정보를 추출한다. 설정된 SessionID가 존재하면 이 ID에 해당되는

    HttpSession객체를 리턴한다. 없으면 새로운 HttpSession객체를 리턴한다.

    새로운 HttpSession객체 생성시 SessionID가 할당되게 된다.

    HttpSession 정보 저장

 

    session.setAttribute("이름", 객체);

 

    HttpSession객체에 유지시키고자 하는 객체(정보)를 성정한다.

    정보는 정보의 이름과 정보가 저장된 주소를 전달하여 설정한다.

 

    HttpSession 정보 추출

 

    session.getAttribute("이름");

 

    주어진 이름에 해당되는 객체(정보)의 실제 저장 주소를 리턴한다.

 

 

Cookie란 Web 서버가 Web 클라이언트에 저장하는 정보로서 클라이언트쪽에 필요한 정보를 저장하고 추출하는 것을 지원하는 기술이다. 연결이 끊겨도 클라이언트마다 특정 정보의 저장이 필요할 때 Cookie 기술을 활용할 수 있다.

 

Servlet으로 구현하는 Cookie 설정과 추출

Servlet API에서는 Cookie를 설정하고 추출하는 기능의 클래스와 메소드를 지원한다.

 

Cookie 설정은 javax.servlet.http Package에서 제공된 Cookie라는 클래스의 객체를 생성하여 HttpServletResponse 인터페이스의 addCookie() 메소드를 사용하여 설정한다.

 

예제학습

//Cookie를 설정하는 기능

//파일명 : CookieSet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CookieSet extends HttpServlet {
    public void doGet (HttpServletRequest req, HttpServletResponse res)

        throws ServletException, IOException {
        Cookie c1 = new Cookie("discount", "20");
        Cookie c2 = new Cookie("item", "sports");
        c2.setMaxAge(60*60*24*3);

        res.setContentType("text/html; charset=KSC5601");
        res.addCookie(c1);
        res.addCookie(c2);
       

        PrintWriter out=res.getWriter();
        out.println("<html><body><h1>Cookie 설정</h1><hr>");
        out.println("설정 완료 !!");
        out.println("</body></html>");
        out.close();
    }
}

 

Cookie 추출은 HttpServletRequest 인터페이스의 getCookie() 메소드를 활용한다.

 

예제학습

//Cookie 정보를 추출하는 기능

//파일명 : CookieGet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CookieGet  extends HttpServlet {
    public void doGet (HttpServletRequest req, HttpServletResponse res)

        throws ServletException, IOException {
        res.setContentType("text/html; charset=KSC5601");
        PrintWriter out=res.getWriter();
        out.println("<html><body><h1>Cookie 추출</h1><hr>");
        Cookie[] cookies = req.getCookies();
        if (cookies != null  && cookies.length > 0) {
            out.println("다음과 같은 Cookie 정보가 전달 되었습니다 :<br>");
            for (int i = 0; i < cookies.length; i++) {
                out.print("Cookie Name: " +cookies[i].getName() +"<br>");
  &n bsp;             out.println("Cookie Value: " +cookies[i].getValue() +"<br>");
            }
        }
       else
           out.println("전달된 Cookie 정보가 없습니다!!");

        out.println("</body></html>");
        out.close();
    }
}


DB연동으로 구현하는 사용자 등록/인증

사용자 인증(Authentication)이란 서버의 자원에 접근하는 계정과 패스워드를 입력받아 등록된 사용자인지를 점검하고 처리하는 기능이다. Servlet에서 사용자 인증을 처리하는 방법으로 Session 개첵를 활용하는 방법을 사용하여 구현해 본다.

 

Servlet에서의 DB 연동은 일반적인 Java Application에서의 DB 연동방법과 동일하다.

 

    JDBC 드라이버 로딩 -> DB 서버 접속 -> SQL문 수행 -> 결과 처리

 

다만 Servlet은 클라이언트로부터의 요청이 많은 특성으로 DB 서버로의 젒속 과정을 효율적으로 처리할 수 있는 Connection Pooling과 같은 다양한 기술들이 활용될 수 있다.

 

예제학습

//1. 회원 등록과 인증을 처리하는 주프레임화면

//파일명 : main.html

<!-- 회원 등록과 인증을 처리하는 주화면 -->
<HTML>
<HEAD>
<TITLE>회원 등록과 인증</TITLE>
</HEAD>
<FRAMESET COLS="30%,70%">
<FRAME SRC=menu.html>
<FRAME NAME=right SRC=about:blank>
</FRAMESET>
</HTML>

 

//2. 메뉴부 화면

//menu.html

<STYLE TYPE=text/css>
a {
    cursor:crosshair;
    font-weight:bolder
}
</STYLE>
<A HREF=insert.html TARGET=right>회원 등록</A><BR>
<A HREF=auth.html TARGET=right>회원 인증</A><BR> 
<A HREF=/edu/servlet/AuthServlet TARGET=right>인증 해제</A><BR>
<A HREF=/edu/servlet/SecureServlet TARGET=right>비밀 정보</A><BR>

 

//3.회원등록정보을 입력받고 호출하는 화면

//화면명 : insert.html

<html>
<head>
<title>
회원 등록과 인증
</title>
</head>
<body>
<h1> 회원 등록 </h1>
<hr> 계정과  패스워드를 입력하여 주십시오
<form action="/edu/dbscript.jsp" method=post>
계   정 : <input type=text name=name> <br>
패스워드 : <input type=password name=passwd> <br>
<input type=submit value=등록>
<input type=reset value=재작성>
</form>
</html>

 

//4.회원인증을 위해 정보를 입력받고 인증과정을 호출하는 화면

//화면명 : auth.html

<html>
<head>
<title>
회원 등록과 인증
</title>
</head>
<body>
<h1 style="background-color:yellow"> 회원 인증 </h1>
<hr> <p style="border-style:double;border-color:green">계정과  패스워드를 입력하여 주십시오 </p>
<form action=/edu/servlet/AuthServlet method=post>
계   정 : <input type=text name=name> <br>
패스워드 : <input type=password name=passwd> <br>
<input type=submit value=인증>
<input type=reset value=재작성>
</form>
</html>

 

//5.DB접속기능의 일반 Class

//파일명 : JdbcOracle.java

import java.sql.*;

public class JdbcOracle {
    public static Connection conn;
    public static Statement stmt;
    static String driver_class = "oracle.jdbc.driver.OracleDriver";
    static String connect_string = "jdbc:oracle:thin:@70.12.220.35:1521:ORA8";
    public static boolean init() {
    try {
        Class.forName(driver_class);
        conn = DriverManager.getConnection(connect_string, "hjava16", "hjava16"); 
        stmt = conn.createStatement();
    return true;
       } catch (Exception e) {
       e.printStackTrace();
       return false;
   }
   }
   public static void cs() {
   try {
     ;      stmt= conn.createStatement();
   } catch (Exception e) {
       e.printStackTrace();
   }
   }
   public static void close() {
   try {
    if (stmt != null)
  stmt.close();
           if (conn != null)
        conn.close();
  } catch (Exception e) {
       e.printStackTrace();
   }
   }
}
 

//6.유저정보등록 기능의 Servlet

//파일명 : InsertAccount.java

import java.io.*;
import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class InsertAccount extends HttpServlet {
    public void doPost (HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
    String name = req.getParameter("name");
    String passwd = req.getParameter("passwd");
    try {
        // DB 연동
        JdbcOracle.init();
        String insertquery = "insert into account values('"+name+"','"+passwd+"')";
        String selectquery = "select name from account where name = '"+name+"'";
  
        ResultSet rs =null;
        rs = JdbcOracle.stmt.executeQuery(selectquery);
        if(rs.next()) {
 &nbs p;          Output.result_msg("이미 존재하는 계정입니다..<br>"+
                "다른 계정을 입력하여 주십시오 !!", res);
        }
        else {
            JdbcOracle.stmt.executeUpdate(insertquery);
            Output.result_msg("계정과 패스워드가 등록 완료되었습니다!! <br> 감사합니다.", res);
        }
   }catch (Exception e) {
       Output.result_msg("오류 발생 : "+ e.toString(), res);
   }finally {
           JdbcOracle.close();
        }
   }
}

 

//7.인증기능의 Servlet

//파일명 : AuthServlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;

 

public class AuthServlet extends HttpServlet {
    public void doPost (HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {
    String name = req.getParameter("name");
    String passwd = req.getParameter("passwd");
    try {
        JdbcOracle.init();
        String selectquery = "select name, passwd from account where name = '"+name+"'";
        ResultSet rs =null;
        rs = JdbcOracle.stmt.executeQuery(selectquery);
        if(rs.next()) {
            if(rs.getString(2).trim().equals(passwd)) {
                if(s ession_set(req, res, name))
                    Output.result_msg("회원 검증 과정이  완료되었습니다 !!", res);
                else
                    Output.result_msg("이미 회원검증 과정을 하셨군요!!", res);
            } else
                Output.result_msg("패스워드가 틀립니다.!!<br>"+
                                          "회원 인증 절차를 다시 수행하여 주십시오..", res);
         } else {
            Output.result_msg("입력하신 계정이 존재하지 않습니다!!", res);
        }
    } catch (Exception e) {
        Output.result_msg("오류 발생 : " +e.toString(), res);
    } finally {
        JdbcOracle.close();
    }
    }

   public boolean session_set(HttpServletRequest req,  HttpServletResponse
      res, String str) throws ServletException, IOException {
   HttpSession session = req.getSession(true);
   if (session.isNew()|| session.getAttribute("name") == null) {
           session.setAttribute("name", str);
    return true;
   } else {
       return false;
   }
   }

   public void doGet (HttpServletRequest req, HttpServletResponse res)
         throws ServletException, IOException {
        HttpSession session = req.getSession(false);
   if (session != null && session.getAttribute("name") != null) {
           session.invalidate();
           Output.result_msg("인증 상태가 해제되었습니다!!", res);
        } else {
           Output.result_msg("인증을 수행하지 않으셨네요!!", res);
        }
   }
}

 

//8.데이터를 브라우저로 전송하기 위한 일반 Class

//파일명 : Output.java

// 데이터를 브라우저로 전송하고자 하는 경우 사용되는 클래스 정의
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Output {
    public static void result_msg (String msg, HttpServletResponse response)
        throws ServletException, IOException  {
            PrintWriter out;
            response.setContentType("text/html;charset=KSC5601");
            out = response.getWriter();
            out.println("<HTML><HEAD><TITLE>");
            out.println("결과");
            out.println("</TITLE></HEAD><BODY bgcolor=\"#FFFFFF\">");
            out.println(msg);
        &n bsp;   out.println("</BODY></HTML>");
            out.close();
   }
}

 

//9.인증여부점검 기능의 Servlet

//파일명 : SecureServlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

 

public class SecureServlet extends HttpServlet {
    public void doGet (HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException {

        HttpSession session = req.getSession(false);
        if (session == null || session.getAttribute("name") == null)
            Output.result_msg("비회원은 보실 수 없는 내용입니다 !!", res);
        else {
            String name =(String)session.getAttribute("name");
            PrintWriter out;
            res.setContentType("text/html;charset=KSC5601");
            out = res.getWriter();
            out.println("<HTML><HEAD><TITLE>");
            out.println("결과");< BR>            out.println("</TITLE></HEAD><BODY bgcolor=\"#FFFFFF\">");
            out.println("비밀 내용(^^)");
            out.println("안녕하세요? "+name+" 회원님 !!");
            out.println("</BODY></HTML>");
            out.close();
        }
    }

반응형