상세 컨텐츠

본문 제목

서블릿 기본

프로그래밍/JAVA

by 라제폰 2009. 1. 23. 16:57

본문

서블릿 기본

 

서버의 기능을 확장시켜주는 자바 객체

서버쪽 컴퓨터에서 실행된다.

javax.servlet 패키지에 의해 지원

성능향상( 간단한 CGI 프로그램에 비해서 10배이상)

프로토콜 및 플랫폼에 독립적

보안성

 

웹 브라우저에서는 애플릿이나 HTML form태그, TCP 소켓등 다양한 형태로 서블릿을 호출할수 있다.

서블릿이 데이타베이스에 연결하거나, RMI를 사용하거나, 다른 언어로 작성된 프로그램 혹은 라이브러리를 호출할 수 있다.

 

★ 서블릿 인터페이스

클라이언트로 부터의 요청에 대한 응답을 생성한다.

서블릿 프로그램의 주 클래스는 javax.servlet.Servlet 인터페이스를 구현하여야 한다.

서블릿 객체는 서블릿 주 클래스 객체이다.

 

기본메소드

init(ServletConfig config) throws ServletException

: 서버는 서블랫 객체를 생성한후, 이 메소드를 한번만 호출함으로써 서블릿 객체가 초기화된다.

getServletConfig 메소드로 반환될수 있도록 config를 객체내에 저장하여야 한다.

ServletConfig getServletConfig()

: ServletConfig는 이 서블랫의 초기화 매개변수 및 서블릿 환경정보를 갖고 있다.

service(ServletRequest req, ServletResponse res) throws ServletException,IOException

: 서버는 클라이언트 요청이 들어올 때 마다 해당 서블릿 객체의 이 메소드를 반복하여 호출한다.

하나의 서블릿 객체가 지속적으로 존재하여 여러개의 클라이언트 요청을 처리할수 있다.

destory()

: 서버 관리자에 의해 서블릿이 제거될때, 이 메소드가 호출된 후 쓰레기 수집된다.

이 메소드내에서는 서블랫 객체와 관련된 자원을 반환하고, 유지되어야 하는 정보는 데이타베이스에 저장해야 한다.

String getServletInfo()

: 저자, 버전, 저작권등에 관한 정보를 담는다. 서블릿 관리 도구에 의해 이용될수 있다.

 

★ GenericServlet 클래스 implements Servlet, ServletConfig

Servlet인터페이스를 구현하는 추상클래스

이 클래스의 하위 클래스는 service 메소드만 구현해도 된다.

init() throws ServletException

: 서블릿 클래스의 간편한 작성을 위해 제공된다.

log(String message)

: 이 서블릿의 클래스 이름과 로그 메시지 message를 서블릿 로그 파일에 기록한다.

log(String message, Throwable t)

: 로그 메시지 message와 함께 발생한 예외 t를 서블릿 로그 파일에 기록한다.

 

★ 서블릿을 호출하기 위한 URL형식

서블릿 엔진, 웹 서버 및 관리자 설정에 따라 URL 지정방식 및 연관된 서블릿 클래스 파일의 위치가 다르다

http://servlethost/servlet/<서블릿 클래스 이름>

http://servlethost/servlet/<서블릿 이름>

 

★ 서블릿과 스레드

여러 웹 클라이언트가 하나의 서블릿에 동시에 접근할때 여러 스레드에 의해 동시에 실행될수 있으므로, 동기화 처리를 하지 않으면 오동작 할수 있다.

synchronized 키워드를 적절히 사용하거나

서블릿 클래스가 SingleThreadModel 인터페이스를 구현하도록 한다.

( 이와같은 서블릿은 하나의 스레드로 실행한다. )

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

public class CounterServlet extends GenericServlet
    // 혹은 implements SingleThreadModel
{
    int count = 0;

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

    public synchronized void service(
        ServletRequest req, ServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType( "text/plain; charset=euc-kr" );
        PrintWriter out = res.getWriter();
        // euc-kr 인코딩 이름이 지원되지 않는 자바 환경에서는
        // 대신 다음을 사용한다.
        // PrintWriter out = new PrintWriter(
        //    new OutputStreamWriter(res.getOutputStream(), "KSC5601") );
        out.println( (++count) + "번째 안녕!" );
        out.close();
    }

    public void destroy()
    {   System.out.println( "destroy()" );
    }
}

 

 

HTTPServlet 추상 클래스

 

HTTP 프로토콜의 요청과 응닫 처리를 편하게 한다.

관련 클래스들이 javax.servlet.http 패키지에 속한다.

HTTP1.1을 지원한다.

GenericServlet의 하위 클래스

 

★ 메소드

service(ServletRequest req, ServletResponse res)

: 다음 service() 메소드를 호출한다.

protected service(HttpServletRequest req, HttpServletResponse res)

: 요청 유형에 따라 다음 do ..() 메소드중에 하나를 호출하므로, 이들 메소드중 적절한 메소드를 재정의 하여야 한다. do..()메소드를 재정의 하지 않으면 BAD_REQUEST 응답을 보낸다.

protected doGet(HttpServletRequest req, HttpServletResponse res)

: GET, HEAD 요청 유형을 처리할 경우, 재정의 하여야 한다.

반복하여 호출되어도 동일한 결과를 얻을 수 있는 경우에 적당하다.

protected doPost(HttpServletRequest req, HttpServletResponse res)

: GET, HEAD 요청 유형을 처리할 경우, 재정의 하여야 한다.

호출될 때 마다 다른 결과를 내야할 때에도 사용할 수 있다.(자료수정및 온라인 쇼핑등)

protected doPut(HttpServletRequest req, HttpServletResponse res)

: HTTP PUT 요청 유형을 처리할 경우, 재정의 하여야 한다.

protected doDelete(HttpServletRequest req, HttpServletResponse res)

: HTTP DELETE 요청 유형을 처리할 경우, 재정의 하여야 한다.

protected doOptions(HttpServletRequest req, HttpServletResponse res)

: 서블릿 클래스에서 do.. 메소드가 재정의 되어 있으면 이에 따라 적절히 HTTP OPTIONS 요청 유형을 처리해 주므로, 일반적인 경우 재정의 할 필요가 없다.

protected doTrace(HttpServletRequest req, HttpServletResponse res)

: HTTP TRACE 요청을 처리해주므로, 일반적으로 재정의 할필요가없다.

protected long getLastModified(HttpServletRequest req)

: 마지막으로 수정된 시각을 나타낸다. 디폴트로 음수값(알수없음을 의미)을 갖는다.

GET 요청 유형을 지원할경우에는 캐쉬 사용을 통한 효율성을 위해서 이 메소드도 재정의 하는것이 바람직하다.

 

ServletResponse 인터페이스

 

클라이언트 요청에 대한 응답을 MIME 자료 형태로 반환하는 데 사용한다.

★ 메소드

setContentType(String type)

: 응답에 포함될 MIME 자료형식을 설정. text타입인 경우, 문자 인코딩을 지정할 수도 있다.

setContentLength(int len)

: 응답에 포함될 자료의 크기를 설정

String getCharacterEncoding()

: 응답에 포함될 문자 자료의 인코딩. 인코딩은 setContentType(...) 메소드 호출에 의해 정해진다.

PrinterWriter getWriter() throws IOException

: 순수문자자료를 응답에 출력하기 위한 스트림. 반환된 스트림은 setContentType(..) 메소드 호출에 의해 주어진 문자 인코딩과의 변환을 수행한다.

ServletOutputStream getOutputStream() throws IOException

: 이진 자료 혹은 혼합 자료를 응답에 출력하기 위한 스트림

 

★ ServletOuputStream 클래스 extneds OutputStream

PrintStream에서와 유사하게 여러가지 Type에 따른 메소드들을 제공한다.

( Type : boolean, char, int, long, float, double, String)

- print(Type val) throws IOException

- println(Type val) throws IOException

- println() throws IOException

println 메소드는 자료를 출력한후 "\r\n"을 출력한다 ( 인터넷 표준)

문자열을 출력할때는 8859-1문자만이 가능하며 한글을 비롯한 다른 문자 집합의 문자열은 getWriter() 를 사용해야 한다.

 

★ HttpSerlvetResponse 인터페이스

HTTP 프로토콜의 응답 생성을 편리하게 한다.

 

★ 응답상태 설정

setStatus(int sc)

: 정상적인 응답의 경우에 상태코드 (sc)를 설정한다.

주로 SC_OK, SC_MOVED_TEMPORARILY 등의 값으로 설정한다.

 

★ 오류, 재지정(redirect) 응답

- sendError(int sc, String msg) throws IOException

: 클라이언트에게 상태 코드 sc및 상세 메시지 msg와 함께 오류 응답을 전송한다.

- sendError(int sc) throws IOException

: 디폴트 메시지로 오류응답을 전송한다.

- sendRedirect(String location) throws IOException

: 클라이언트에게 재지정 URL(location)과 함께 재지정 응답을 전송한다.

 

★ 응답에 헤더 설정

헤더 이름(name) 에 대하여 그 값(value)를 설정한다.

setHeader(String name, String value)

setIntHeader(String name, int value)

setDateHeader(String name, long date)

boolean containsHeader(String name)

 

서블릿에서의 다국어 및 현대 한글 문서 출력

 

다음과 같은 경우에는 출력 문서의 인코딩을 KSC5601 대신 Unicode 혹은 UTF8을 사용한다.

유니코드 2.0의 모든 현대한글을 사용하는 문서

다국어 문서

윈도우즈용 넷스케이프에서 한글 유니코드 출력을 보기위해서는 'Edit/Preference/Appearance/Fonts' 에서 Unicode 인코딩에 사용될 폰트를 한글 폰트로 설정한다.

 

Unicode

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

public class UnicodeServlet extends HttpServlet
{
    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType( "text/html; charset=csUnicode" );
        // PrintWriter out = res.getWriter();
        PrintWriter out = new PrintWriter(
            new OutputStreamWriter(res.getOutputStream(), "UnicodeLittle") );
                                  
        String title = "유니코드 출력 테스트";
        out.println( "<HTML><HEAD><TITLE>" );
        out.println( title );
        out.println( "</TITLE></HEAD><BODY>" );
        out.println( "<H1>" + title + "</H1>" );
        out.println( "유니코드 인코딩의 8859-1문자: "
                     + "\u00a1\u00a2\u00a3\u00a4<p>" );
        out.println( "유니코드 인코딩의 현대 한글 문자: "
                     + "\uac00\uac01\uac02\uac03" );
        out.println( "</BODY></HTML>" );
        out.close();
    }
}

UTF-8

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

public class UTF8Servlet extends HttpServlet
{
    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType( "text/html; charset=utf-8" );
        // PrintWriter out = res.getWriter();
        // utf-8 인코딩 이름이 지원되지 않는 자바 환경에서는
        // 대신 다음을 사용한다.
        PrintWriter out = new PrintWriter(
            new OutputStreamWriter(res.getOutputStream(), "UTF8") );
        String title = "UTF-8 출력 테스트";
        out.println( "<HTML><HEAD><TITLE>" );
        out.println( title );
        out.println( "</TITLE></HEAD><BODY>" );
        out.println( "<H1>" + title + "</H1>" );
        out.println( "UTF-8 인코딩의 8859-1문자: "
                     + "\u00a1\u00a2\u00a3\u00a4<p>" );
        out.println( "UTF-8 인코딩의 현대 한글 문자: "
                     + "\uac00\uac01\uac02\uac03" );
        out.println( "</BODY></HTML>" );
        out.close();
    }
}

 

ServletRequest 인터페이스

 

클라이언트로 부터 요청에 대한 정보를 얻는 데 사용된다.

 

★ 네트워크 연결정보

String getServerName()

: 요청을 받은 서버의 호스트 이름을 반환

int getServerPort()

: 요청이 들어온 서버포트를 반환

String getRemoteHost()

: 요청을 보낸 클라이언트의 호스트 이름을 반환

String getRemoteAddr()

: 요청을 보낸 클라이언트의 IP주소를 반환

String getProtocol()

: 요청의 프로토콜과 버젼을 <protocol>/<major version>.<minor version> 의 형태로 반환

String getScheme()

: 요청의 URL 스킴 ("http","https", "ftp", 등등)

 

★ 요청 매개변수 정보

웹서버에 전달되는 요청 매개변수 정보는 GET 메소드를 사용한 요청인 경우에는 URL이 포함되고 POST 메소드를 사용한 요청인 경우에는 입력 스트림으로 전달된다.

Enumeration getParameterNames()

: 요청에 포함된 모든 매개변수값 이름을 알수 있다.

String[] getParameter(String name)

: 요청 매개변수의 첫번째 값을 스트링으로 반환

String[] getParameterValues(String name)

: 요청 매개변수의 값들을 스트링 배열로 반환

 

★ 요청에 포함된 자료및 자료에 관한 정보

String getContentType()

: 요청에 포함된 자료의 타입 , 알수없으면 null을 반환

String getCharacterEncoding()

: 요청에 포함된 문자자료의 인코딩

int getContentLength()

: 요청에 포함된 자료의 크기. 알수없으면 -1을 반환

BufferReader getReader() throws IOException

: 요청에 포함된 순수 문자자료를 읽기위한 스트림 . 반환된 스트림을 getCharacterEncoding()의 값에 따라 적절히 문자 인코딩을 처리한다.

ServletInputStream getInputStream() thorws IOException

: 요청에 포함된 이진 자료혹은 혼합자료를 읽기위한 스트림

 

★ 애트리뷰트

다른 메소드로는 알아낼수 없는 특수한 요청 정보의 검색

Object getAttribute(String name)

setAttribute(String name, Object val)

Enumeration getAttributeNames()

다음은 표준 애트리 뷰트이다.

- "javax.net.ssl.cipher_suit"

: SSL을 통하여 요청이 들어 온경우, 사용되는 SSL암호화 기술이름(String)

- "javax.net.ssl.peer_certificates"

: SSL을 통하여 요청이 들어 온경우, 클라이언트를 입증하기 위한 X.509인증서 체인 (javax.security.cert.X509Certificate[])

- "java.xnet.ssl.session"

: SSL을 통하여 요청이 들어 온경우, 사용되는 SSL 세션객체 체인(javax.net.ssl.SSLSession)

 

★ SerlvletInputStream 클래스 extends InputStream

- int readLine(byte[] buf, int off, int len)

: '\n' 혹은 입력의 끝을 만날때 까지 '\n'을 포함하여 buf로 읽어들인다.

읽어들인 바이트 갯수를 반환. 스트림의 끝을 만나면 -1을 반환

 

HttpServletRequest 인터페이스

 

HTTP 프로토콜의 요청 처리를 편리하게 한다.

ServletRequest의 하위 인터페이스

 

★ 인증 (authentication)

- String getRemoteUser()

: 요청을 만든 사용자의 이름 반환. 알수 없으면 null 반환

- String getAuthType()

: 요청이 요구하는 인증(authentication) 방식을 반환. 없으면null 반환

 

★ 요청 정보

헤더 이름('name')은 대소문자 구분하지 않는다.

Enumeration getHeaderNames()

: 모든 헤더 이름을 알아낸다. 웹서버에 따라 이 기능이 지원되지 않을수 있으며, 이러한 경우은 null반환

String getHeader(String name)

: 헤더 이름 'name'의 값을 반환

int getIntHeader(String name)

: 헤더이름 'name'값을 int로 반환 없으면 -1반환

long getDateHeader(String name)

: 헤더이름 'name' 의 값을 날짜를 나타내는 long으로 반환. 없으면 -1 반환

 

★ 요청 URI에 관한 정보

StringBuffer HttpUtils.getRequestURL(HttpSerlvetRequest req)

: 클라이언트의 요청 URL(query String은 제외)

String getMethod()

: "GET", "HEAD", "POST" 혹은 기타 HTTP확장 요청 유형을 반환

String getRequestURI()

: 요청 URI를 URL로 반환

String getPathInfo()

: 요청 URI중에서 서블릿 경로와 질의 스트링 사이 부분을 반환. 없으면 null을 반환

String getPathTranslated()

: getPathInfo()를 실제 경로로 변환

String getQueryString()

: 서블릿 URI의 질의 스트링 부분을 반환 , 없으면 null을 반환

 

<html> <head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>HTML Form 테스트</title>
<body>
<h2>HttpServletRequest GET 테스트</h2>
<p><form action="/servlet/HttpServletRequestTest" method="GET">
<table>
<tr><td>이름:</td>
<td><input type="TEXT" name="name" size=10></td></tr>
<tr><td>주소:</td>
<td><input type="TEXT" name="address" size=50></td></tr>
</table>
<input type="SUBMIT" value="전송">,
</form>

<h2>HttpServletRequest POST 테스트</h2>
<p><form action="/servlet/HttpServletRequestTest" method="POST">
<table>
<tr><td>이름:</td>
<td><input type="TEXT" name="name" size=10></td></tr>
<tr><td>주소:</td>
<td><input type="TEXT" name="address" size=50></td></tr>
</table>
<input type="SUBMIT" value="전송">,
</form>
</body> </html>

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

public class HttpServletRequestTest extends HttpServlet
{
    public void doPost( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        doGet(req, res);
    }
   
    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType("text/html; charset=euc-kr");
        PrintWriter out = res.getWriter();
        // euc-kr 인코딩 이름이 지원되지 않는 자바 환경에서는
        // 대신 다음을 사용한다.
        // PrintWriter out = new PrintWriter(
        //    new OutputStreamWriter(res.getOutputStream(), "KSC5601") );

        out.println("<html>");
        out.println("<head><title>HttpServletRequest 테스트</title></head>");
        out.println("<body>");

        out.println("<h1>서버 정보:</h1>");
        out.println("<pre>");
        print(out, "Server name", req.getServerName());
        print(out, "Server port", req.getServerPort());
        out.println("</pre><p>");

        out.println("<h1>클라이언트 정보:</h1>");
        out.println("<pre>");
        print(out, "Remote host", req.getRemoteHost());
        print(out, "Remote address", req.getRemoteAddr());
        print(out, "Remote user", req.getRemoteUser());
        print(out, "Authorization scheme", req.getAuthType());
        out.println("</pre><p>");

        out.println("<h1>요청 헤더 정보:</h1>");
        Enumeration e = req.getHeaderNames();
        out.println("<pre>");
        while (e.hasMoreElements())
        {
            String name = (String)e.nextElement();
            out.println(" " + name + ": " + req.getHeader(name));
        }
        out.println("</pre><p>");

        out.println("<h1>요청 URI에 대한 정보:</h1>");
        out.println("<pre>");
        print(out, "Request URL", HttpUtils.getRequestURL(req).toString());
        print(out, "Request protocol", req.getProtocol());
        print(out, "Request URL scheme", req.getScheme());
        print(out, "Request method", req.getMethod());
        print(out, "Request URI", req.getRequestURI());
        print(out, "Servlet path", req.getServletPath());
        print(out, "Path info", req.getPathInfo());
        print(out, "Path translated", req.getPathTranslated());
        print(out, "Query string", req.getQueryString());
        out.println("</pre><p>");

        out.println("<h1>요청 매개변수 정보:</h1>");
        out.println("<pre>");
        e = req.getParameterNames();
        while (e.hasMoreElements())
        {
            String name = (String)e.nextElement();
            String vals[] = (String []) req.getParameterValues(name);
            if (vals != null)
            {
                out.print("<b> " + name + "</b>: ");
                out.println(vals[0] + "(" + toHangul(vals[0]) + ")" );
                for( int i = 1; i < vals.length; i++ )
                    out.println("           " + vals[i] +
                                toHangul(vals[i]) + ")" );
            }
        }
        out.println("</pre><p>");

        out.println("<h1>요청 자료 정보:</h1>");
        out.println("<pre>");
        print(out, "Content Type", req.getContentType());
        print(out, "Character Encoding", req.getCharacterEncoding());
        print(out, "Content Length", req.getContentLength());
        out.println("</pre><p>");

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

    private void print( PrintWriter out, String name, String value )
    {
        out.print(" " + name + ": ");
        out.println(value == null ? "(없음)" : value);
    }

    private void print( PrintWriter out, String name, int value )
    {
        out.print(" " + name + ": ");
        if (value == -1)
        {
            out.println("(없음)");
        } else
        {
            out.println(value);
        }
    }

    public String getServletInfo()
    {
        return "A servlet that shows the request headers sent by the client";
    }

    private static String toHangul( String str )
        throws UnsupportedEncodingException
    {
        if ( str == null )
            return null;
        return new String( str.getBytes("8859_1"), "KSC5601" );
    }
}

 

서블릿 이름, 서블릿 초기화 매개변수, URL 매핑

 

★ 서블릿 이름과 초기화 매개변수 설정

서블릿에 이름을 부여함으로써, 서블릿 클래스 이름대신에 부여된 서블릿 이름을 사용하여 서블릿을 호출하고 관리할수 있다.

 

★ ServletConfig 인터페이스

서블릿 초기화 매개변수 및 서블릿 환경정보 검색

Servlet 인터페이스의 getServletConfig() 메소드를 호출하여 객체를 얻는다.

Enumeration getInitParameterNames()

String getInitParameter(String name)

ServletContext getServletContext()

: 서블릿 환경정보

 

 

configtest.code=ServletConfigTest
configtest.initparams=\
        username=kim,\
        password=java

persistentCounter.code=PersistentCounterServlet
persistentCounter.initparams=\
        counterFile=C:\\example\\web\\counter.dat

upload.code=FileUploadServlet
upload.initparams=\
        uploadFile=C:\\example\\web\\upload.dat

survey.code=SurveyServlet
survey.initparams=\
        surveyDir=C:\\example\\web\\survey

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

public class ServletConfigTest extends HttpServlet
{
    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType("text/html; charset=euc-kr");
        PrintWriter out = res.getWriter();
        // euc-kr 인코딩 이름이 지원되지 않는 자바 환경에서는
        // 대신 다음을 사용한다.
        // PrintWriter out = new PrintWriter(
        //    new OutputStreamWriter(res.getOutputStream(), "KSC5601") );

        out.println("<html>");
        out.println("<head><title>ServletConfig 테스트</title></head>");
        out.println("<body>");
        out.println("<h1>서블릿 초기화 매개변수 정보</h1>");

        Enumeration enum = getInitParameterNames();
        out.println("<pre>");
        if (enum != null)
        {
            while (enum.hasMoreElements())
            {
                String param = (String) enum.nextElement();
                out.println(" " + param + ": " + getInitParameter(param));
            }
        }
        out.println("</pre><p>");

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

    public String getServletInfo()
    {
        return "서블릿 개발자 정보...";
    }
}

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

public class PersistentCounterServlet extends HttpServlet
{
    int count;
    String counterFile;

    public void init( ServletConfig config )
        throws ServletException
    {
        super.init(config);
        counterFile = getInitParameter("counterFile");
        // 화일에 저장된 내용으로부터 `count' 초기화.
        if (counterFile == null)
        {
            throw new UnavailableException(this,
                "counter 저장 화일이 지정되지 않았음" );
        }
        count = readStoredCounter();
    }

    public synchronized void doGet(
        HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType("text/html; charset=euc-kr");

        PrintWriter out = res.getWriter();
        String title = "PersistentCounterServlet 테스트";
        out.println( "<HTML><HEAD><TITLE>" );
        out.println( title );
        out.println( "</TITLE></HEAD><BODY>" );
        out.println( "<H1>" + title + "</H1>" );
        out.println( "<P>당신은 " + (++count) + "번째 방문하셨습니다." );
        out.println( "</BODY></HTML>" );
        out.close();
        if ( count % 10 == 0 )
            writeStoredCounter( count );
    }

    public void destroy()
    {
        writeStoredCounter( count );
    }

    private int readStoredCounter()
    {
        DataInputStream dis = null;
        try
        {
            dis = new DataInputStream(
                new FileInputStream( counterFile ) );
            return dis.readInt();
        } catch( IOException ex )
        {   return 0;
        } finally
        {
            try
            {   if ( dis != null )
                    dis.close();
            } catch( IOException ex )
            {   ex.printStackTrace();
            }
        }
    }

    private void writeStoredCounter( int count )
    {
        DataOutputStream dos = null;
        try
        {
            dos = new DataOutputStream(
                new FileOutputStream( counterFile ) );
            dos.writeInt( count );
        } catch( IOException ex )
        {   ex.printStackTrace();
        } finally
        {
            try
            {   if ( dos != null )
                dos.close();
            } catch( IOException ex )
            {   ex.printStackTrace();
            }
        }
    }
}

 

설문서블릿

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>SurveyServlet 테스트</title></head>
<body>
<form action="/servlet/survey" method=POST>
<input type=hidden name=survey value=01.txt>
본 설문은 CGI 프로그램 대신에 자바 서블릿을 사용하였을 때의
편리성 및 성능에 대하여 조사함으로써
보다 향상된 웹서비스를 제공하기 위한 것입니다.<p>

조금은 불편하시더라도 성의껏 답변해 주시면 대단히 감사하겠습니다.<p>

<h4>1. 서블릿을 작성함으로써 CGI 프로그램을 작성하는 경우에 비하여
작성 속도가 평균 몇배 향상되었습니까?</h4><br>
<input type=radio name=develop value=less>감소<br>
<input type=radio name=develop value=1>1배<br>
<input type=radio name=develop value=2>2배<br>
<input type=radio name=develop value=3>3배<br>
<input type=radio name=develop value=5-more>5배 이상<br>

<h4>2. 서블릿을 사용함으로써 CGI 프로그램을 사용하는 경우에 비하여
실행 속도가 평균 몇배 향상되었습니까?</h4><br>
<input type=radio name=speed value=less>감소<br>
<input type=radio name=speed value=1>1배<br>
<input type=radio name=speed value=2>2배<br>
<input type=radio name=speed value=3>3배<br>
<input type=radio name=speed value=5-more>5배 이상<br>

<h4>3. 자바 가능 웹서버는 어느것을 사용하십니까?</h4><br>
<input type=checkbox name=server value=servletrunner>JSDK의 servletrunner<br>
<input type=checkbox name=server value=JavaWebServer1.1>자바 웹 서버 1.1<br>
<input type=checkbox name=server value=JavaWebServer1.0.x>자바 웹 서버 1.0x<br>
<input type=checkbox name=server value=apache>아파치<br>

<h4>4. 서블릿에서 부족하거나 불편하다고 생각되는 점은 무엇입니까?</h4><br>
<textarea name=comment rows=7 cols=60></textarea><br>
<hr><br>
<input type=submit value=전송합니다><input type=reset value=취소합니다>
</form>
</body></html>

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

public class SurveyServlet extends HttpServlet
    implements SingleThreadModel
{
    String surveyDir;
   
    public void init( ServletConfig config )
        throws ServletException
    {
        super.init(config);
        surveyDir = getInitParameter("surveyDir");
        if (surveyDir == null)
        {
            throw new UnavailableException(this,
                "Directory for saving survey results is not given" );
        }
    }

    public void doPost( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType("text/html; charset=euc-kr");
        PrintWriter toClient = res.getWriter();

        try
        {
            // 설문 결과를 저장할 화일을 연다.
            String surveyName = req.getParameter("survey");
            FileWriter surveyFile = new FileWriter( surveyDir
                + System.getProperty("file.separator")
                + surveyName, true);
            PrintWriter toFile = new PrintWriter(surveyFile);

            // 전송된 폼 데이타를 화일에 저장한다.
            toFile.println("<BEGIN>");
            Enumeration names = req.getParameterNames();
            while(names.hasMoreElements())
            {
                String name = (String)names.nextElement();
                if( name.equals("submit") )
                    continue;

                toFile.print( name + ":" );
                String[] values = req.getParameterValues(name);
                for( int i = 0; i < values.length; i++ )
                {
                    if ( i == 0 )
                        toFile.print(" ");
                    else
                        toFile.print(", ");
                    toFile.print( toHangul( values[i] ) );
                }
                toFile.println();
            }

            toFile.println("<END>");
            toFile.close();

            // 사용자에게 감사 메시지를 전달한다.
            toClient.println("<html><head><title>설문조사 결과"
                             + "</title></head>");
            toClient.println("<body>설문에 응해주셔서 감사합니다.</body>");
            toClient.println("</html>");

        } catch( IOException e )
        {
            e.printStackTrace();
            toClient.println("<html><head><title>설문조사 오류"
                             + "</title></head><body>");
            toClient.println("문제가 발생하였습니다.");
            toClient.println("설문에 다시 응해주시기 바랍니다.");
            toClient.println("</body></html>");
        } finally
        {
            toClient.close();
        }
    }

    private static String toHangul( String str )
        throws UnsupportedEncodingException
    {
        if ( str == null )
            return null;
        return new String( str.getBytes("8859_1"), "KSC5601" );
    }
}

 

파일 업로드 서블릿

 

웹 서버로 파일을 업로드 하기 위해서는 FORM 태그에서 method 및 enctype 속성값을 각각 "post", "multipart/form-data" 으로 한다.

업로드되는 파일은 웹 서버에 MIME 형식으로 전달되므로 MIME 헤더를 적절히 파싱하여 처리한다.

 

<html> <head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>화일 업로드 테스트</title>
<body>
<h1>화일 업로드 테스트</h1>
<br>
<form action="/servlet/upload" method=post enctype=multipart/form-data>
<input type=file size=50 name="upload">
<input type=reset value="취소"><br>
<input type=submit value="화일 전송">
</body>
</html>

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

public class FileUploadServlet extends HttpServlet
{
    String uploadFile;
   
    public void init( ServletConfig config )
        throws ServletException
    {
        super.init(config);
        uploadFile = getInitParameter("uploadFile");
        if (uploadFile == null)
        {
            throw new UnavailableException(this,
                "Directory for saving loaded files is not given" );
        }
    }

    public void doPost(HttpServletRequest req,
                       HttpServletResponse res)
        throws ServletException, IOException
    {
        ServletInputStream fromClient = req.getInputStream();
        res.setContentType("text/html; charset=euc-kr");
        PrintWriter toClient = res.getWriter();
        // euc-kr 인코딩 이름이 지원되지 않는 자바 환경에서는
        // 대신 다음을 사용한다.
        // PrintWriter toClient = new PrintWriter(
        //    new OutputStreamWriter(res.getOutputStream(), "KSC5601") );

        String name;
        String filename = null;
        String contentType = null;
        FileOutputStream toFile = null;

        try
        {
            int ind = req.getContentType().indexOf("boundary=");
            if (ind == -1)
                throw new IOException();
            String boundary = req.getContentType().substring(ind+9);
            if (boundary == null)
                throw new IOException();
            String endBoundary = "--" + boundary + "--";

            String line;
            String lowerLine;
            byte[] lineBuf = new byte[1024*8];
            int lineLen;

            // 바운더리 표식 제거
            fromClient.readLine(lineBuf, 0, lineBuf.length);

            // Content-Disposition 헤더 처리
            lineLen = fromClient.readLine(lineBuf, 0, lineBuf.length);
            line = new String(lineBuf, 0, lineLen);
            lowerLine = line.toLowerCase();
            ind = lowerLine.indexOf("content-disposition:") + 20;
            ind = lowerLine.indexOf("form-data;", ind) + 10;
            int nameStart = lowerLine.indexOf("name=\"", ind) + 6;
            int nameEnd = lowerLine.indexOf("\"", nameStart);
            if ( nameStart == -1 || nameEnd == -1 )
                throw new IOException();
            name = line.substring(nameStart, nameEnd);
            int filenameStart = lowerLine.indexOf("filename=\"", ind) + 10;
            int filenameEnd = lowerLine.indexOf("\"", filenameStart);
            if ( filenameStart != -1 && filenameEnd != -1 )
                filename = line.substring(filenameStart, filenameEnd);

            // Content-Type 헤더가 있으면 처리한 후, 블랭크 라인을 읽어들인다.
            lineLen = fromClient.readLine(lineBuf, 0, lineBuf.length);
            line = new String(lineBuf, 0, lineLen);
            lowerLine = line.toLowerCase();
            if (lowerLine.startsWith("content-type:"))
            {
                contentType = line.substring(13).trim();
                lineLen = fromClient.readLine(lineBuf, 0, lineBuf.length);
                line = new String(lineBuf, 0, lineLen);
            }
            if ( ! line.equals("\r\n") )
                throw new IOException();
           
            // 데이타를 읽어들여서 화일에 저장한다.
            toFile = new FileOutputStream(uploadFile);
            byte[] lineBuf2 = new byte[1024*8];
            int lineLen2 = 0;
            lineLen = fromClient.readLine(lineBuf, 0, lineBuf.length);
            if (lineLen == -1)
                throw new IOException();
            line = new String(lineBuf2, 0, lineLen2, "8859_1");
            while (! line.startsWith(endBoundary))
            {
                toFile.write(lineBuf2, 0, lineLen2);
                System.arraycopy(lineBuf, 0, lineBuf2, 0, lineLen);
                lineLen2 = lineLen;
                lineLen = fromClient.readLine(lineBuf, 0, lineBuf.length);
                if (lineLen == -1)
                    throw new IOException();
                line = new String(lineBuf, 0, lineLen, "8859_1");
            }               
            if ( lineLen2 >= 2)
                toFile.write(lineBuf2, 0, lineLen2-2);
            toFile.close();

            // 웹 문서 생성
            toClient.println("<html><head><title>화일 업로드 결과"
                             + "</title></head>");
            toClient.println("<body>다음 화일이 업로드되었습니다.");
            toClient.println("<br><b>name: " + name + "<br>");
            toClient.println("<b>filename: " + filename + "<br>");
            toClient.println("Content-Type: " + contentType + "<br>");
            toClient.println("</body></html>");
        } catch( IOException e )
        {
            toClient.println("<html><head><title>화일 업로드 오류"
                             + "</title></head><body>");
            toClient.println("문제가 발생하였습니다.");
            toClient.println("다시 업로드하시기 바랍니다.");
            toClient.println("</body></html>");
            e.printStackTrace();
        } finally
        {
            toFile.close();
            toClient.close();
        }
    }
}

 

ServletContext 인터페이스

 

서블릿의 환경정보 검색 및 서블릿간 통신

 

★ 서블릿 환경정보

int getMajorVersion()

: 서블랫 API 주 버전

int getMinorVersion()

: 서블릿 API 종 버젼

String getServerInfo()

String getMimeType(String file)

 

★ 컨텐트 위치 정보

String getRealPath(String path)

URL getResource(String path) throws MalformedURLException

: 컨텐트 위치를 서블릿 환경에 독립적인 방식으로 접근하기 위한 URL

InputStream getResourceAsStream(String path)

 

★ 서블릿간 통신

특정 그룹의 서블릿이 공유하는 애트리뷰트를 만든다.

서블릿 엔진 혹은 웹 서버의 관리 설정에 의해 그룹화된 서블릿들이 1개의 서블릿 컨택스트를 공유한다.

RequestDispatcher getRequestDispatcher(String urlpath)

: urlpath를 처리하는 서블릿에 대한 참조를 반환한다. 다른 서블릿에 요청을 넘기거나 다른 서블릿의 실행결과를 이용하고자 할때 사용한다.

Object getAttribute(String name)

SevletContext getContext(String uripath)

setAttribute(String name, Object val)

removeAttribute(String name)

Enumeration getAttributeNames()

 

★ 로그메시지

log(String message)

log(String message, Throwable ex)

 

★ RequestDispatcher 인터페이스

forword(ServletRequest request, SerlvetResponse response) throws ServletException, IOException

: 다른 서블릿에 요청 처리를 넘길때 사용

include((ServletRequest request, SerlvetResponse response) throws ServletException, IOException

서블릿 내에서 사용할 수 있는 SSI(ServersideInclude) 의 일종

다른 서블릿 혹은 자바 서버페이지의 결과를 이 서블릿의 반응에 포함 시키고자 할때 사용

response내의 PrintWriter, OuputStream만 영향을 받는다.

 

★ 서블릿에서의 네트워킹

서블릿은 일반적으로 애플릿 보다는 제약이 덜 하므로 네트워크나 데이타 베이스등 다양한 자원에 손쉽게 접근할 수 있다.

자바로 만든 서브를 서블릿에서 실행시킬수 있다.

자바 가상 머쉰의 공유로 인한 효율성

서버의 자동 실행에 따른 관리 편리성

익명 서버 포트사용에 의한 서버 포트 충동 문제 해결

:서블릿이 익명포트로 서버를 실행 시키고 실제 포트를 알아내어 그 포트번호를 클라이언트(애플릿,애플리케이션)에게 전달해 주면, 클라이언트는 그 포트번호로 접속한다.

 

<html><head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=euc-kr">
</head>

<body>
<h1>채팅 서블릿 애플릿</h1>
<applet code="ChatServletClient.class" width=1 height=1>
<param name="serverLoc" value="/servlet/ChatServlet">
</applet>
</body>
</html>

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

public class ChatServlet extends HttpServlet
{
    int port;
   
    public void init( ServletConfig config )
        throws ServletException
    {
        super.init( config );
        try
        {
            ChatServer server = new ChatServer(0); // 자유 포트 사용
            port = server.socket.getLocalPort();
            server.start();
        } catch( IOException ex )
        {
            throw new ServletException(ex.getMessage());
        }
    }

    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        DataOutputStream toClient
            = new DataOutputStream(res.getOutputStream());
        toClient.writeInt( port );
        toClient.close();
    }   
}

import java.io.*;
import java.net.*;
import java.applet.*;

public class ChatServletClient extends ChatClient
{
    public void init()
    {
        try
        {
            super.init();
            URL url = new URL(getCodeBase(), getParameter("serverLoc"));
            DataInputStream dis = new DataInputStream(url.openStream());
            int port = dis.readInt();
            portNum.setText( String.valueOf(port) );
        } catch ( IOException ex )
        {
            ex.printStackTrace();
        }
    }
}

 

 

URL을 이용한 네트워킹

 

URLConnection

        |

HttpURLConnection

 

URL이 나타내는 자원을 입출력 할수 있다.

URL에 지정된 프로토콜(HTTP, FTP등) 에 접근할수 있다.

CGI 프로그램 , 서블릿과 통신하는데 유용하다.

- 서블릿의 GET,POST 등의 요청메소드를 지원함으로써 애플릿이나 자바 애플리케이션에서 HTML 폼 태그를 대신할수 있다.

- 웹 서버로 자료를 전송할 수 있으므로, 자료를 업로드 할수 있다.

 

java.net.URLConnection 클래스

 

★ 생성

URL 클래스의 opneConnection() 메소드는 해당 URLConnection 클래스를 반환한다.

URL getURL()

★ 셋업 매개변수 설정

이들값의 설정을 생략하여도 절절한 값으로 이미 설정되어 있다.

boolean URLConnection.defaultAllowUserInteraction

boolean allowUserInteraction

boolean doInput

boolean doOutput

boolean ifModifiedSince

boolean useCashes

★ 연결

connect()

★ 요청 매개변수

setRequestProperty(String key, String value)

String getRequestProperty(String key)

★ 요청 데이타

OutputStream getOutputStream()

★ 반응 헤더 추출

String getHeaderField(String name)

int getHeaderFieldInt(String name, int Default)

long getHeaderFieldDate(String name, long Default)

String getContentType()

String getContentEncoding()

int getContentLength()

long getDate()

long getLastModified()

long getExpiration()

★ 반응 데이타

Object getContent()

InputStream getInputStream

 

HttpURLConnection 클래스

 

HTTP 프로토콜을 사용하여 접속시 다양한 기능 이용

HTTP 프로토콜을 지정한 URL객체의 openConnection 메소드가 반환하는 객체의 실제 자료형은 HttpURLConnection 클래스이다.

HttpURLConnection.setFollowRedirects(boolean set)

boolean HttpURLConnection.getFollowRedirects()

: HTTP redirect 응답을 받은 경우의 재접속 여부 디폴트는 true

String requestMethod throws ProtocolException

: HTTP 요청 메소드 "GET", "POST", "HEAD", "OPTION", "PUT", "DELETE", "TRACE"

int getResponseCode() throws IOException

: HTTP 응답코드

HTTP_OK, HTTP_NOT_FOUND, HTTP_UNAUTHORIZED, HTTP_NOT_AUTHORITATIVE, HTTP_CREATED, HTTP_ACCEPTED, HTTP_NO_CONTENT, HTTP_RESET, HTTP_PARTIAL, HTTP_MULT_CHOICE, HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_SEE_OTHER, HTTP_NOTMODIFIED, HTTP_BAD_REQUEST, HTTP_PAYMENT_REQUIRED, HTTP_FORBIDDEN, HTTP_BAD_METHOD, HTTP_NOT_ACCEPTABLE, HTTP_CLIENT_TIMEOUT, HTTP_CONFLICT, HTTP_GONE, HTTP_LENGTH_REQUIRED, HTTP_PRECON_FAILED, HTTP_ENTITY_TOO_LARGE, HTTP_REQ_TOO_LONG, HTTP_UNSUPPORTED_TYPE, HTTP_SERVER_ERROR, HTTP_INTERNAL_ERROR, HTTP_UNAVAILABLE, HTTP_USE_PROXY, HTTP_PROXY_AUTH, HTTP_GATEWAY_TIMEOUT, HTTP_BAD_GATEWAY

String getResponseMessage() throws IOException

: HTTP 응답메시지 ("HTTP/1.0 200 OK","HTTP/1.0 404 Not Found" 등등)

boolean usingProxy()

: HTTP 프록시를 통한 접속여부.

InputStream getErrorStream()

disconnect()

 

★ URL 인코딩, 디코딩

String URLEncoder.encode(String str)

: str을 x-www-form-urlencoded 인코딩으로 변환한다. CGI 프로그램 혹은 서블릿과 통신할때 필요하다

String URLDecoder.decode(Strng str)

: x-www-form-urlencoded 인코딩의 스트링 str을 복원한다.

 

import java.net.*;
import java.io.*;

class URLConnectionTest
{
    public static void main(String args[])
        throws MalformedURLException, IOException
    {
        URL url = new URL( args[0] );
        URLConnection con = url.openConnection();
        System.out.println( con.getHeaderField("Content-Type") );
        System.out.println( con.getHeaderField("Content-Length") );
        System.out.println( con.getContentType() );
        System.out.println( con.getContentEncoding() );
        System.out.println( con.getContentLength() );
        System.out.println( new java.util.Date(con.getDate()) );
        System.out.println( new java.util.Date(con.getExpiration()) );
        System.out.println( new java.util.Date(con.getLastModified()) );

        System.out.println( con.getContent() );
        InputStream in = con.getInputStream();
        for(int ch; (ch = in.read()) != -1;)
            System.out.write( ch );
        System.out.flush();
    }
}

<html> <head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<title>URL POST 테스트</title>
<body>
<h1>URL POST 테스트</h1>
<applet code="URLPostTest.class" width=500 height=500>
<param name="serverLoc" value="/servlet/FormServlet">
</applet>
</body>
</html>

import java.awt.*;
import java.io.*;
import java.net.*;

public class URLPostTest extends java.applet.Applet
{
    public static void main(String args[])
        throws MalformedURLException, IOException
    {
        URL url = new URL( args[0] );
        URLConnection con = url.openConnection();
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        con.setRequestProperty("Content-Type",
                               "application/x-www-form-urlencoded");

        // 요청 데이타 전송
        PrintWriter toServer = new PrintWriter(con.getOutputStream());
        String content = "name=" + URLEncoder.encode("홍길동") +
            "&address=" + URLEncoder.encode("Seoul");
        System.out.println(content);
        toServer.println(content);
        toServer.close();

        // 반응 데이타 출력
        println( "Content Type: " + con.getContentType() );
        println( "Content Encoding: " + con.getContentEncoding() );
        println( "Content Length: " + con.getContentLength() );

        InputStreamReader isr = null;
        if ( con.getContentEncoding() != null )
            isr = new InputStreamReader( con.getInputStream(),
                                         con.getContentEncoding() );
        else
            isr = new InputStreamReader( con.getInputStream() );
        BufferedReader br = new BufferedReader( isr );
        for(String line; (line = br.readLine()) != null;)
            println( line );
    }

    static void println(String mesg)
    {  
        if ( isApplet )
            msgArea.append( mesg + "\n" );
        else
            System.out.println( mesg );
    }

    static boolean isApplet = false;
    static TextArea msgArea;

    public void init()
    {
        isApplet = true;
        msgArea  = new TextArea();
        setLayout(new BorderLayout());
        add( msgArea, "Center" );
        try
        {
            URL url = new URL(getCodeBase(), getParameter("serverLoc"));
            System.out.println(url);
            main( new String[] { url.toString() } );
        } catch( IOException ex )
        {   ex.printStackTrace();
        }
    }
}

 

쿠키

 

(정보를 클라이언트에서 관리 trafiic이 높다)

 

                       요청, 반응시(쿠키포함)

웹브라우저   <------------------------>   웹서버

                       요청(쿠키포함), 반응

 

웹 서버와 웹브라우저 사이의 HTTP 연결들을 서로 이어주는 데이타

사용자 설정, 간단한 로긴 기능, 데이타 수집등

웹 서버가 쿠키를 반응 헤더로서 웹 브라우저에 전달하면 웹브라우저는 쿠키를 메모리에 기억한 후 ,차후 연결시에 요청헤데로서 그 쿠기값을 서버에 전달한다.

 

★ Cookie클래스

new Cookie(String name, String value)

String name

: 쿠키의 이름

String value

: 쿠키의 값, 이진 자료형인경우 BASE64로 인코딩하는 것이 바람직하다.

String domain

: 웹 브라우저가 쿠키를 전달할 호스트들의 도메인 이름. 디폴트로, 본래쿠키를 생성한 웹서버에게만 전달한다.

String path

: 이 path로 시작하는 URL 을 요청할때만 웹 브라으저가 쿠키를 전달한다. 디폴트로 쿠키가 생성될 당시의 URL

int maxAge

: 쿠키의 수명(초단위)

- 0: 즉각 쿠키가 제거되게 한다.

- 음수 (디폴트) 웹브라우저가 종료될때까지

boolean secure

: 보안 프로토콜 https를 통해서만 절달될수 있다.

int version

: 쿠키규약의 버젼

 

★ HttpServletResponse 인터페이스 메소드

addCookie(Cookie cookie)

: 웹 브라우저에 전송할 쿠키. 여러개를 전송할수 있다.

★ HttpServletRequest 인터페이스 메소드

: Cookie[] getCookies()

: 웹 브라우저가 전송한 쿠키들

 

세션

 

특정 웹 브라우저 사용자와 웹 서버와의 HTTP연결들을 하나로 이어준다.

세션은 쿠키 혹은 URL 리라이팅(rewriting)을 적절히 사용하여 구현된다.

 

쿠키를 사용하는 경우 보다 프로그래밍하기가 용이하다.

처음 로그인시에만 사용자 ID와 암호를 검증하고 세션 ID를 발급하여. 이후에는 발급된 세션ID만 검증함으로써 기존 HTTP인증 방법 보다 효율적이다.

HTML 폼 hidden 속성을 사용하는 것보다 세션 데이타를 서버측에서 관리함으로써 교환되는 자료의 양이 적어 효율적이다.

 

HTTPSession 인터페이스

boolean isNew()

: 클라이언트가 세션에 참가하고 있으면 true

String getID()

: 세션 식별자

long getCreationTime()

: 세션이 생성된 시각

long getLastAccessedTime()

: 사용자가 마지막으로 세션을 사용한 시각. 오래된 세션을 닫는 등 세션관리에 사용될수 있다.

putValue(String name, Object value)

: 이 세션에서 유지되는 데이타의 이름과 값의 설정. value가 HttpSessionBindingListener 인터페이스를 구현한 경우, valueBound() 메소드가 호출된다.

Object getValue(String name)

: 이 세션에서 유지되는 데이타의 이름과 값의 검색

removeValue(String name)

: 이름이 name인 세션 데이타 객체가 HttpSessionBindingListener 인터페이스를 구현한 경우 valueUnbound() 메소드가 호출된다.

String [] getVaueNames()

int maxInactiveInterval

: 이 세션이 유지되기 위한 클라이언트 요청의 최대 시간 간격

invalidate()

: 세션을 제거한다.

 

★ HttpSessionBindingListener 인터페이스

valueBound(HttpSessionBindingEvent event)

valueUnBound(HttpSessionBindingEvent event)

 

★  HttpSessionBindingEvent 클래스

String getName()

HttpSession getSession()

 

★ HttpServletRequest 인터페이스의 메소드

HttpSession getSession(boolean create=true)

: 이 요청과 연관된 세션을 반환한다. create가 true이면 이 요청과 연관된 세션이 없을경우 새로운 세션을 생성한다.

String getRequestedSessionId()

boolean isRequestedSessionIdFromCookie()

boolean isRequestedSessionIdFromURL()

boolean isRequestedSessionIdValid()

 

★ HttpServletResponse 인터페이스의 메소드

다음은 쿠키를 지원하지 않는 웹브라우저를 위한 URL 리라이팅의 구현을 위해 사용된다.( 필요한 경우 세션 식별자가 URL에 포함된다.

String encodeURL(String url)

String encodeRedirectURL(String url)

 

SessionServlet.java 는 특정 디렉토리(/session/내의 모든 무서가 접근되기 전에 발급된 세션 ID를 요구한다.)

홀수번 방문할 경우에는 해당 문서를 전송하고, 짝수번 방문할때는 세션 ID와 세션 데이타(방문횟수)를 전송한다.

세션 ID없이 접근하는 클라이언트의 요청은 LoginServlet.java 로 리다이렉트한다.

 

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

public class LoginServlet extends HttpServlet
{
    Properties database = new Properties();

    public void init(ServletConfig config)
        throws ServletException
    {
        super.init(config);
        database.put("guest", "guest");
        database.put("홍길동", "java");
    }

    String first = "<html> <head>\r\n"
        + "<title>로그인</title> </head>\r\n"
        + "<body><h1> 로그인</h1>\r\n";
    String bad = "<p> 로그인 실패! 다시 입력하십시오.\r\n";
    String second
        = "<p><form action=\"LoginServlet\" method=\"POST\">\r\n"
        + "<table><tr><td>아이디</td>\r\n"
        + "<td><input type=text name=\"id\" size=15></td></tr>\r\n"
        + "<tr><td>암호</td>\r\n"
        + "<td><input type=password name=\"password\" size=15></td>\r\n"
        + "<td><input type=submit value=\"로그 인\"></td></tr>\r\n"
        + "</table> </form> </body> </html>\r\n";

    public void doGet( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        res.setContentType("text/html; charset=euc-kr");
        PrintWriter out = res.getWriter();
        out.write( first );
        out.write( second );
        out.close();
    }

    public void doPost( HttpServletRequest req, HttpServletResponse res )
        throws ServletException, IOException
    {
        String id = toHangul(req.getParameter("id"));
        String password = req.getParameter("password");
   
        // 아이디와 암호를 화일, 데이타베이스등으로부터 읽어들일 수도 있다.
        if ( database.getProperty(id) == null
             || ! database.getProperty(id).equals(password) )
        {
            res.setContentType("text/html; charset=euc-kr");
            PrintWriter out = res.getWriter();
            out.write( first );
            out.write( bad );
            out.write( second );
            out.close();
            return;
        }

        // 세션 생성후, a.html로 리다이렉트..
        HttpSession session = req.getSession(true);
        res.sendRedirect("/session/a.html");
        return;
    }

    public static String toHangul( String str )
        throws UnsupportedEncodingException
    {
        if ( str == null )
            return null;
        return new String( str.getBytes("iso-8859-1"), "euc-kr" );
    }
}

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

public class SessionServlet extends HttpServlet
{
    public void init(ServletConfig config)
        throws ServletException
    {
        super.init(config);
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res)
        throws ServletException, IOException
    {
        // 세션 추출
        HttpSession session = req.getSession(false);

        // 처음 접속시에는 LoginServlet으로 리다이렉트.
        if ( session == null )
        {
            res.sendRedirect("/servlet/LoginServlet");
            return;
        }

        Integer counter = (Integer) session.getValue("counter");
        if (counter == null)
            counter = new Integer(1);
        else
            counter = new Integer(counter.intValue() + 1);
        session.putValue("counter", counter);

        if ( counter.intValue() % 2 == 1 )
        {   // 해당 HTML 문서를 읽어들여 전송한다.
            res.setContentType("text/html; charset=euc-kr");
            ServletOutputStream out = res.getOutputStream();
            // InputStream included = getServletConfig().getServletContext()
            //    .getResourceAsStream(req.getRequestURI());
            // Workaround for Bug in JRun 2.3
            String filename = getServletConfig().getServletContext()
                .getRealPath(req.getRequestURI());
            InputStream included = new FileInputStream(filename);
            byte[] buf = new byte[1024];
            for( int c; (c = included.read(buf)) != -1; )
                out.write(buf, 0, c);
            included.close();
            out.close();
        } else
        {   // 세션 ID, 세션 데이타 출력
            res.setContentType("text/html; charset=euc-kr");
            PrintWriter out = res.getWriter();
            out.println("<html><body><h1>세션 정보</h1>");
            out.println("<br>세션 ID: " + session.getId());
            out.println("<br>세션 데이타 (방문 횟수): " + counter );
            out.close();
        }
    }
}


관련글 더보기