레이블이 jsp인 게시물을 표시합니다. 모든 게시물 표시
레이블이 jsp인 게시물을 표시합니다. 모든 게시물 표시

2014년 4월 7일 월요일

[Servlet/Jsp] headFirst - Ch13 - filter, wrapper


0. 환경

macbook-pro 13” 2012 mid / 10GB
tomcat7
교재: Head First Servlet/Jsp, 한빛미디어, 2012


1. 학습목표

1) filter
2) wrapper


2. filter

필터는 자바 컴포넌트로서 서블릿으로 요청이 넘어가기 전에 요청을 가로채 어떤 처리를 진행

용도

  1. request filter
    • 보안관련 내용 확인
    • 요청헤더와 바디 포멧팅 수정
    • 요청 감시나 기록
  2. response filter
    • 응답 스트림 압축
    • 응답 스트림에 내용 추가 및 수정
    • 완전히 새로운 응답 생성

특징

  1. 필터는 모듈식으로 DD에 설정하고 실행 순서를 설정할 수 있음
  2. 필터가 데이터 형태를 변경하는 경우 그 순서를 지정할 수 있으나 그 의존성을 필터 내부에 삽입할 필요는 없음
  3. filter는 자신의 고유한 API를 가지며 Container는 filter의 API를 앎
  4. Container는 filter의 생명주기를 관리

Filter Interface

javax.servlet.Filter

public interface Filter {
    // init() 메소드는 반드시 구현
    // Container가 Filter를 인스턴스화 할 때 실행
    // Filter 호출 전 뭔가 설정할 것이 있는 경우 (일반적으로 FilterConfig 객체를 내부 field에 저장)
    public void init( FilterConfig ) throws ServletException;

    // 실제 filter를 구현
    public void doFilter ( ServletRequest, ServletResponse, FilterChain ) throws IOException, ServletException;

    // Conteriner가 Filter의 인스턴스를 제거할 때 호출 ( 삭제 전 수행할 코드 )
    public void destroy();
}

FilterChain Interface

  1. DD를 통해 filter의 순서를 지정할 수 있고 FilterChain이 다음에 실행할 filter를 판단함으로써 순차적 진행을 가능하게 함
  2. Filter.doFilter()와 다름
  3. FilterChain.doFilter()는
    • 다음에 호출할 filter가 무엇인지 파악하여 doFilter()를 실행
    • 체인의 마지막 filter인 경우 Servler의 service() 메소드 호출

javax.servlet.FilterChain

public interface FilterChain {
    public void doFilter ( ServletRequest, ServletResponse ) throws IOException, ServletException;
}

개념적인 스택 모델

  1. 요청이 들어오면 Filter A의 doFilter() 메소드 호출
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 메소드를 만날 때까지 수행
  2. Conatiner는 Filter B의 doFilter() 메소드를 Stack의 제일 위에 쌓음
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 메소드를 만날 때까지 수행
  3. Container는 Servlet A의 service() 메소드를 Stack의 제일 위에 쌓음
  4. Conatiner는 service() 메소드의 실행 완료시 Stack에서 제거
  5. Container는 Filter B의 doFilter() 메소드로 돌아옴
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 이후의 로직을 수행
    • 이후 로직에서 response관련 작업
  6. Container는 Filter B의 doFilter() 실행 완료시 Stack에서 제거
  7. Container는 Filter A의 doFilter() 메소드로 돌아옴
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 이후의 로직을 수행
    • 이후 로직에서 response관련 작업
  8. Container는 Filter A의 doFilter() 실행 완료시 Stack에서 제거
  9. Container는 응답 완료함

requset filter / response filter

// Filter를 구현한 Class 중..
// .
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) {
    // 요청을 처리
    chain.doFilter ( request, response );
    // 응답을 처리
}
// .

3. request filter

실행 순서 지정

  1. url-pattern으로 일치하는 필터가 체인에 순서대로 들어감
    • 일치하는 모든 필터를 모두 체인에 넣고 실행
  2. 이후 servlet-name으로 일치하는 필터를 찾아 그 정의된 순서대로 체인에 등록
<web-app ...>
    <servlet> ... </servlet>

    <!-- filter-name, filter-class는 반드시 필요한 항목 -->
    <!-- init-param은 옵션 -->
    <filter>
        <filter-name>BeerRequest</filter-name>
        <filter-class>com.example.web.BeerRequestFilter</filter-class>
        <init-param>
            <param-name>LogFileName</param-name>
            <param-value>UserLog.txt</param-value>
        </init-param>
    </filter>

    <!-- filter-mapping 선언규칙 -->
    <!-- filter-name은 반드시 필요하며, filter 선언을 찾기 위해 필요 -->
    <!-- url-pattern, servlet-name 중 하나는 반드시 필요 -->
    <filter-mapping>
        <filter-name>BeerRequest</filter-name>
        <!-- url-pattern은 어떤 웹 어플리케이션 리소들에 필터를 적용할지 정의 -->
        <url-patterm>*.do</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>BeerRequest</filter-name>
        <!-- 필터를 적용할 웹 어플리케이션 하나를 정의 -->
        <servlet-name>AdviceServlet</servlet-name>
    </filter-mapping>
</web-app>

RequestDispatcher 요청시

forward, include, request dispatch, error를 통해 웹 리소스를 요청하는 경우에도 필터 적용 가능

<filter-mapping>
    <filter-name>MonitorFilter</filter-name>
    <url-pattern>*.do</url-pattern>
    <!-- dispatcher 항목을 0 .. 4까지 포함 가능 -->
    <!-- request는 client가 요청할 때 적용한다는 의미 -->
    <!-- dispatcher 항목이 없는 경우 request가 DEFAULT -->
    <dispatcher>request</dispatcher>
        그리고 / 또는
    <!-- include는 client가 포함될 때 적용 -->
    <dispatcher>include</dispatcher>
        그리고 / 또는
    <!-- forward는 client가 요청을 다른 곳으로 넘길 때 적용 -->
    <dispatcher>forward</dispatcher>
        그리고 / 또는
    <!-- error는 error 핸들러는 호출했을 때 적용 -->
    <dispatcher>error</dispatcher>
</filter-mapping>

4. response filter

심각한 문제점

  1. filter는 Servlet으로 request, response객체를 전달
    • Servlet에게 다시 response 객체를 전달받기를 기다림
  2. Servlet은 자신이 받은 인자가 filtering 되었다는 사실을 모름
    • 출력에 대한 제어는 Container가 가져감
    • Container는 결과를 Client에게 전달
  3. filter는 response 객체를 전달받기 위해 계속 기다림

해결책

4가지의 wrapper class를 사용하여 Response 객체를 새롭게 정의한 후 Servlet에게 전달
Servlet에서 새 Response 객체에 기록시 Client로 전달되기 전에 제어 가능


5. Wrapper

랩퍼 클래스는 현재 구현하려는 타입의 객체를 내부에 가짐
모든 메소드 호출을 위임할 동일한 타입의 클래스 객체에 대한 참조를 내부에서 가짐


Written with Dec7.

2014년 4월 6일 일요일

[Servlet/Jsp] headFirst - Ch5 - listener, attribute


0. 환경

macbook-pro 13” 2012 mid / 10GB
tomcat7
교재: Head First Servlet/Jsp, 한빛미디어, 2012


1. 학습목표

1) ServletContext 초기화 파라미터
2) 서블릿 속성 생존범위
3) 웹 컨테이너 요청 처리 모델
4) 웹 컨테이너 생명주기 이벤트 모델
5) ResquestDispacher 매커니즘


2. 서블릿 초기화 파라미터

  • 서블릿도 초기화 파라미터가 존재
  • Container가 서블릿을 초기화할 때 단 한번만 초기화 파라미터를 읽음
  • 이름/값 쌍이 ServletConfig안에 기록시 서블릿이 다시 배포되지 않는 한 DD를 수정해도 바뀌지 않음

실행 흐름

  1. Container는 DD를 읽음
  2. Container는 새로운 ServletConfig 인스턴스 생성 (서블릿당 하나씩)
    • 서블릿 생성자에서는 이 메소드를 호출할 수 없음
  3. Container는 init-param에 있는 값들을 이름-값 쌍으로 읽음
  4. Conatiner는 ServletConfig 객체에 이름-값으로 된 초기화 파라미터 설정
  5. Container는 XXXServlet.class 인스턴스 생성
  6. Container는 ServletConfig의 참조를 인자로 Servlet의 init() 메소드 호출

ServletConfig

초기화 파라미터에 접근할 수 있는 능력

javax.servlet.ServletConfig

public abstract interface ServletConfig {

    // context정보 (Servlet 설정정보)를 담고 있는 ServletContext를 반환
    public abstract ServletContext getServletContext();
    public abstract String getInitParameter(String);
    public abstract Enumeration getInitParameterNames();
    public abstract String getServletName();
}

DD (Web.xml)

<servlet>
    <servlet-name>Tests</servlet-name>
    <servlet-class>TestInitParams</servlet-class>

    <!-- DD의 <servlet>항목 안에 <init-param>으로 작성 -->
    <init-param>
        <param-name>adminEmail</param-name>
        <param-value>dec7@abc.com</param-value>
    </init-param>
</servlet>

Servlet 코드

// ServletConfig getServletConfig ();
// 모든 servlet은 상속받은 getServletConfig() 메소드를 가짐
out.println(getServletConfig().getInitParameter("adminEmail"));

3. 컨텍스트 초기화 파라미터

모든 웹 어플리케이션에서 이용할 수 있음 (JSP, Servlet)
ServletContext와 ServletConfig는 다른 객체로 다른 이름공간을 이용

실행흐름

  1. Container는 DD를 읽음
  2. 항목을 읽고 각각의 이름-값 쌍을 만듦
  3. Container는 ServletContext 객체를 생성
  4. Container는 생성한 컨텍스트 초기화 파라미터 이름-값에 대한 참조를 init() 인자로 전달
  5. Web Application에 있는 모든 Servlet과 JSP는 ServletContext에 접근 가능

ServletContext

javax.servlet.ServletContext

public abstract interface jServletContext {
  public static final String TEMPDIR = "javax.servlet.context.tempdir";
  public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";

  public abstract String getContextPath();
  public abstract jServletContext getContext(String);
  public abstract int getMajorVersion();
  public abstract int getMinorVersion();
  public abstract int getEffectiveMajorVersion();
  public abstract int getEffectiveMinorVersion();
  public abstract String getMimeType(String);
  public abstract Set getResourcePaths(String);
  public abstract URL getResource(String) throws MalformedURLException;
  public abstract InputStream getResourceAsStream(String);
  public abstract RequestDispatcher getRequestDispatcher(String);
  public abstract RequestDispatcher getNamedDispatcher(String);
  public abstract jServlet getServlet(String) throws jServletException;
  public abstract Enumeration getServlets();
  public abstract Enumeration getServletNames();
  public abstract void log(String);
  public abstract void log(Exception, String);
  public abstract void log(String, Throwable);
  public abstract String getRealPath(String);
  public abstract String getServerInfo();
  public abstract String getInitParameter(String);
  public abstract Enumeration getInitParameterNames();
  public abstract boolean setInitParameter(String, String);
  public abstract Object getAttribute(String);
  public abstract Enumeration getAttributeNames();
  public abstract void setAttribute(String, Object);
  public abstract void removeAttribute(String);
  public abstract String getServletContextName();
  public abstract jServletRegistration.Dynamic addServlet(String, String);
  public abstract jServletRegistration.Dynamic addServlet(String, jServlet);
  public abstract jServletRegistration.Dynamic addServlet(String, Class);
  public abstract jServlet createServlet(Class) throws jServletException;
  public abstract jServletRegistration getServletRegistration(String);
  public abstract Map getServletRegistrations();
  public abstract FilterRegistration.Dynamic addFilter(String, String);
  public abstract FilterRegistration.Dynamic addFilter(String, Filter);
  public abstract FilterRegistration.Dynamic addFilter(String, Class);
  public abstract Filter createFilter(Class) throws jServletException;
  public abstract FilterRegistration getFilterRegistration(String);
  public abstract Map getFilterRegistrations();
  public abstract SessionCookieConfig getSessionCookieConfig();
  public abstract void setSessionTrackingModes(Set);
  public abstract Set getDefaultSessionTrackingModes();
  public abstract Set getEffectiveSessionTrackingModes();
  public abstract void addListener(String);
  public abstract void addListener(EventListener);
  public abstract void addListener(Class);
  public abstract EventListener createListener(Class) throws jServletException;
  public abstract descriptor.JspConfigDescriptor getJspConfigDescriptor();
  public abstract ClassLoader getClassLoader();
  public abstract void declareRoles(String...);
  public abstract String getVirtualServerName();
}

DD (Web.xml)

<servlet>
    <servlet-name>Tests</servlet-name>
    <servlet-class>TestInitParams</servlet-class>
</servlet>

<!-- 전체 어플리케이션을 위한 항목 / <web-app> 항목에 포함 -->
<context-param>
    <param-name>adminEmail</param-name>
    <param-value>dec7@abc.com</param-value>
</context-param>

Servlet Code

out.println ( getServletContext().getInitParameter("adminEmail") );

4. Listener

컨텍스트 초기화가 이루어질 때 파라미터를 읽은 뒤 특정 코드를 실행시키고 싶을 때

실행흐름

  1. Container는 DD를 읽음
    • context-param, listen
  2. Container는 Application에 공유할 ServletContext 객체 생성
  3. Container는 컨텍스트 초기화 파라미터의 이름-값 String쌍을 만듦
  4. Container는 String쌍을 ServletContext객체에 설정
  5. Container는 ServletContextListener를 상속받아 만든 Class를 인스턴스화 시킴
  6. Container는 contextInitialized()메소드를 호출하고 인자로 ServletContextEvent를 전달
    • ServletContextEvent 객체를 이용하여 ServletContext에 접근
    • ServletContext로 컨텍스트 초기화 파라미터 값을 읽음
  7. Listener가 ServletContextEvent에게 ServletContext에 대한 참조를 요청
  8. Listener가 ServletContext에게 초기화 파라미터의 값을 요청
  9. Listener는 초기화 파라미터를 이용해 객체를 생성
  10. Listener는 ServletContext.setAttribute(“newObj”, obj)를 이용하여 생성된 객체를 설정
  11. Container는 새로운 Servlet을 생성
    1. 초기화 파라미터로 ServletConfig 생성
    2. ServletContext에 대한 참조를 설정
    3. Servlet init() 메소드 호출
  12. Servlet은 요청을 받고 ServletContext에게

Written with Dec7.

[Servlet/Jsp] headFirst - Ch4 - Response, Request


0. 환경

macbook-pro 13” 2012 mid / 10GB
tomcat7
교재: Head First Servlet/Jsp, 한빛미디어, 2012


1. 학습목표

HTTP 메소드

1) 사용 목적 및 각 HTTP메소드의 프로토콜의 기술적 특징 설명
2) 각 HTTP메소드에 대응되는 HttpServlet 메소드
3) 클라이언트(웹 브라우저)가 이 메소드를 사용하면 발생하는 작업들

HttpServletRequest

1) interface로
2) html 폼, http request 헤더, cookie 정보 읽기

HttpServletResponse

1) interface로
2) http response 헤더 설정
3) content-type 설정
4) text stream or byte stream 얻는 법
5) http request를 다른 url로 redirect하는 법
6) response에 cookie를 설정하는 법

servlet

1) 생명주기, 이벤트와 각각 목적에 대한 설명


2. Servlet 구조

Servlet interface

service(), init(), destroy()가 생명주기 메소드

javax.servlet.Servlet

public abstract interface Servlet {
    // method 
    public abstract void init(ServletConfig) throws ServletException;
    public abstract void service(ServletRequest, ServletResponse) throws ServletException, IOException;
    public abstract void destroy();
    public abstract ServletConfig getServletConfig ();
    public abstract String getServletInfo();
}

GenericServlet Abstract Class

대부분의 Servlet 메소드가 구현됨
이 클래스를 직접 상속받아 클래스를 생성할 일은 거의 없으나 Servlet 행위를 대부분 구현

javax.servlet.GenericServlet

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    // field
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings;
    private transient ServletConfig config;

    // constructor
    public GenericServlet();

    // method
    public void init(ServletConfig) throws ServletException;
    public void init() throws ServletException;
    public void destroy();

    public ServletContext getServletContext();
    public ServletConfig getServletConfig();
    public String getServletInfo();
    public String getServletName();

    public String getInitParameter(String);
    public Enumeration getInitParameterNames();

    public void log(String);
    public void log(String, Throwable);
}

HttpServlet Abstract Class

Servlet의 HTTP적인 측면을 반영하기 위해 service() 메소드를 재정의
service()는 오직 HTTP요청, HTTP응답만을 받아들이고 다른 어떤 Servlet 요청와 응답은 받지 않는다는 의미

javax.servlet.http.HttpServlet

public abstract class HttpServlet extends GenericServlet {
    // field
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings;

    // constructor
    public HttpServlet();

    // method
    public void service(ServletRequest, ServletResponse) throws ServletException, IOException;
    protected void service(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;

    protected void doGet(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doHead(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doPost(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doPut(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doDelete(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doOptions(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;
    protected void doTrace(HttpServletRequest, HttpServletRespons) throws ServletException, IOException;

    private void maybeSetLastModified(HttpServletResponse, long);
    private java.lang.reflect.Method[] getAllDeclaredMethods(java.lang.Class c);  
}

3. Servlet 생명주기

오직 하나의 상태를 가짐: 초기화

초기화 되지 않았다는 의미

  1. 초기화되는 중
    • 생성자 실행
    • init() 실행
  2. 소멸되는 중
    • destory() 실행
  3. 존재하지 않음

생성 흐름

서블릿의 일생은 로딩할 때부터 시작되고 이 작업은 Container가 시작할 때 이루어짐

  1. Container는 Servlet Class를 로딩
  2. Servlet 인스턴스화
    • Servlet Class 생성자 실행
    • 생성자의 실행은 존재하지 않음에서 초기화됨 상태로 이동을 의미
    • 초기화됨은 서비스 준비가 됐다는 의미
    • 하지만 생성자는 단지 객체를 만드는 작업으로 완벽한 Servlet은 아님
  3. init()
    • 일생 중 한번만 실행
    • service() 전에 호출
  4. service()
    • 초기화된 Servlet
    • 일생의 대부분 유지
    • 요청이 들어올 때마다 새로운 Thread에서 실행
    • 클라이언트 요청을 handling (doPost(), doGet()…)
  5. destroy()
    • 초기화된 Servlet
    • 일생 중 한번만 실행
    • 죽기전 자원을 정리할 기회 제공

중요한 순간

method 명 호출되는 시점 목적 재정의 여부
init() 서블릿 인스턴스 생성 후,
service() 호출 전
초기화 가능
DB접속, 다른 객체에 서블릿 등록
service() 최초 클라이언트 요청 받았을 때 HTTP method를 참조하여
어떤 HttpServlet method를 호출할지 판단
거의 안함
doPost(), doGet()을 재정의 한 후
service()가 실행하도록 함
doGet()
doPost()
service()가
HTTP method 참조한 후 호출
코딩 둘 중 하나는 반드시
재정의 하지 않는 경우 없다고 판단
  • 최초 클라이언트에게 요청받으면 Container는 새로운 Thread를 생성하거나 Thread pool에서 하나를 할당함
  • 클라이언트가 요청한 횟수만큼 thread가 생성됨
  • Container의 정책에 따라 최대 thread 개수를 설정
    • 이 숫자가 넘으면 기다려야 함
  • service() 메소드는 항상 자신만의 스택에서 호출됨
    • service()가 완료되는 시점이 thread가 종료되는 시점
  • 재정의 하지 않은 경우
    • init(): GenericServlet에서 호출
    • service(): HttpServlet에서 호출
    • doPost(), doGet(): 반드시 재정의 필요
  • 서블릿 클래스 하나에 다수의 인스턴스라는 말을 잘못됨 (SingleThreadModel)
  • 클라이언트의 요청마다 새로운 Request, Response 객체 생성

4. init() 메소드

ServletConfig 객체와 ServletContext객체에 접근가능

ServletConfig 객체

  • Servlet 당 1개
  • ServletContext에 접근하기 위해 ServletConfig 이용
  • Servlet 배포시 Servlet마다 설정된 정보 (숨기고 싶은 것들.. DB정보)
    • 파라미터 값은 DD에서 설정, 내용 수정시 재배포

ServletContext 객체

  • Web Application마다 1개 (App Context가 올바른 용어)
  • Web Application의 파라미터 정보를 읽기 위해 사용됨
    • 파라미터 값은 DD 속 설정됨
    • 서버정보 파악하기 위함 (컨테이너 이름,버전, 지원API …)

5. Request, Response

ServletRequest Interface

javax.servlet.ServletRequest

public abstract interface ServletRequest {

  public abstract Object getAttribute(String);
  public abstract Enumeration getAttributeNames();
  public abstract String getCharacterEncoding();
  public abstract void setCharacterEncoding(String) throws UnsupportedEncodingException;
  public abstract int getContentLength();
  public abstract long getContentLengthLong();
  public abstract String getContentType();
  // Request의 입력 스트림
  public abstract ServletInputStream getInputStream() throws IOException;

  // Request의 Parameter 정보
  public abstract String getParameter(String);
  public abstract Enumeration getParameterNames();
  public abstract String[] getParameterValues(String);
  public abstract Map getParameterMap();

  // server는 클라이언트의 요청을 리스링하는 서버
  public abstract String getServerName();
  public abstract int getServerPort();
  // local은 클라이언트의 요청을 처리하기 위한 스레드 (새로운 포트 생성)
  public abstract String getLocalName();
  public abstract String getLocalAddr();
  public abstract int getLocalPort();
  // remote는 서버의 원격지: 즉 클라이언트
  public abstract String getRemoteAddr();
  public abstract String getRemoteHost();
  public abstract int getRemotePort();

  public abstract String getProtocol();
  public abstract String getScheme();
  public abstract BufferedReader getReader() throws IOException;
  public abstract void setAttribute(String, Object);
  public abstract void removeAttribute(String);
  public abstract Locale getLocale();
  public abstract Enumeration getLocales();
  public abstract boolean isSecure();
  public abstract RequestDispatcher getRequestDispatcher(String);
  public abstract String getRealPath(String);
  public abstract ServletContext getServletContext();
  public abstract AsyncContext startAsync() throws IllegalStateException;
  public abstract AsyncContext startAsync(ServletRequest, ServletResponse) throws IllegalStateException;
  public abstract boolean isAsyncStarted();
  public abstract boolean isAsyncSupported();
  public abstract AsyncContext getAsyncContext();
  public abstract DispatcherType getDispatcherType();
}

HttpServletRequest interface

javax.servlet.http.HttpServletRequest

public abstract interface HttpServletRequest extends ServletRequest {

  public static final String BASIC_AUTH = "BASIC";
  public static final String FORM_AUTH = "FORM";
  public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
  public static final String DIGEST_AUTH = "DIGEST";

  public abstract String getAuthType();
  // Request에 관련된 쿠키
  public abstract Cookie[] getCookies();
  // 클라이언트플랫폼 정보 및 브라우저 정보
  public abstract String getHeader(String);
  public abstract int getIntHeader(String);  // == Integer.parseInt(getHeader(arg0))
  public abstract long getDateHeader(String);
  public abstract Enumeration getHeaders(String);
  public abstract Enumeration getHeaderNames();
  // Request의 Http method
  public abstract String getMethod();
  public abstract String getPathInfo();
  public abstract String getPathTranslated();
  public abstract String getContextPath();
  public abstract String getQueryString();
  public abstract String getRemoteUser();
  public abstract boolean isUserInRole(String);
  public abstract Principal getUserPrincipal();
  public abstract String getRequestedSessionId();
  public abstract String getRequestURI();
  public abstract StringBuffer getRequestURL();
  public abstract String getServletPath();
  // 클라이언트의 세션 정보
  public abstract HttpSession getSession(boolean);
  public abstract HttpSession getSession();
  public abstract String changeSessionId();
  public abstract boolean isRequestedSessionIdValid();
  public abstract boolean isRequestedSessionIdFromCookie();
  public abstract boolean isRequestedSessionIdFromURL();
  public abstract boolean isRequestedSessionIdFromUrl();
  public abstract boolean authenticate(HttpServletResponse) throws IOException, ServletException;
  public abstract void login(String, String) throws ServletException;
  public abstract void logout() throws ServletException;
  public abstract Collection getParts() throws IOException, ServletException;
  public abstract Part getPart(String) throws IOException, ServletException;
  public abstract HttpUpgradeHandler upgrade(Class) throws IOException, ServletException;
}

ServletResponse Interface

javax.servlet.ServletResponse

public abstract interface ServletResponse {
  // method
  public abstract String getCharacterEncoding();
  public abstract String getContentType();
  // response의 출력 스트림
  public abstract ServletOutputStream getOutputStream() throws IOException;
  // response의 문자 출력
  public abstract PrintWriter getWriter() throws IOException;
  public abstract void setCharacterEncoding(String);
  public abstract void setContentLength(int);
  public abstract void setContentLengthLong(long);
  public abstract void setContentType(String);
  public abstract void setBufferSize(int);
  public abstract int getBufferSize();
  public abstract void flushBuffer() throws IOException;
  public abstract void resetBuffer();
  public abstract boolean isCommitted();
  public abstract void reset();
  public abstract void setLocale(Locale);
  public abstract Locale getLocale();
}

HttpServletResponse Interface

javax.servlet.http.HttpServletResponse

public abstract interface HttpServletResponse extends ServletResponse {
  // field
  public static final int SC_CONTINUE = 100;
  public static final int SC_SWITCHING_PROTOCOLS = 101;
  public static final int SC_OK = 200;
  public static final int SC_CREATED = 201;
  public static final int SC_ACCEPTED = 202;
  public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
  public static final int SC_NO_CONTENT = 204;
  public static final int SC_RESET_CONTENT = 205;
  public static final int SC_PARTIAL_CONTENT = 206;
  public static final int SC_MULTIPLE_CHOICES = 300;
  public static final int SC_MOVED_PERMANENTLY = 301;
  public static final int SC_MOVED_TEMPORARILY = 302;
  public static final int SC_FOUND = 302;
  public static final int SC_SEE_OTHER = 303;
  public static final int SC_NOT_MODIFIED = 304;
  public static final int SC_USE_PROXY = 305;
  public static final int SC_TEMPORARY_REDIRECT = 307;
  public static final int SC_BAD_REQUEST = 400;
  public static final int SC_UNAUTHORIZED = 401;
  public static final int SC_PAYMENT_REQUIRED = 402;
  public static final int SC_FORBIDDEN = 403;
  public static final int SC_NOT_FOUND = 404;
  public static final int SC_METHOD_NOT_ALLOWED = 405;
  public static final int SC_NOT_ACCEPTABLE = 406;
  public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
  public static final int SC_REQUEST_TIMEOUT = 408;
  public static final int SC_CONFLICT = 409;
  public static final int SC_GONE = 410;
  public static final int SC_LENGTH_REQUIRED = 411;
  public static final int SC_PRECONDITION_FAILED = 412;
  public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
  public static final int SC_REQUEST_URI_TOO_LONG = 414;
  public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
  public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
  public static final int SC_EXPECTATION_FAILED = 417;
  public static final int SC_INTERNAL_SERVER_ERROR = 500;
  public static final int SC_NOT_IMPLEMENTED = 501;
  public static final int SC_BAD_GATEWAY = 502;
  public static final int SC_SERVICE_UNAVAILABLE = 503;
  public static final int SC_GATEWAY_TIMEOUT = 504;
  public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

  // method
  public abstract void addCookie(Cookie);
  public abstract boolean containsHeader(String);
  public abstract String encodeURL(String);
  public abstract String encodeRedirectURL(String);
  public abstract String encodeUrl(String);
  public abstract String encodeRedirectUrl(String);
  public abstract void sendError(int, String) throws IOException;
  public abstract void sendError(int) throws IOException;
  public abstract void sendRedirect(String) throws IOException;
  public abstract void setDateHeader(String, long);
  public abstract void addDateHeader(String, long);
  // 이미 존재하는 값을 덮어씀
  // 이 메소드 사용이 어떤 헤더라도 하나 이상의 값을 가질 수 없음
  public abstract void setHeader(String, String);
  // 값을 하나 더 추가
  public abstract void addHeader(String, String);
  // 이미 존재하는 헤더의 값을 정수값으로 대체
  public abstract void setIntHeader(String, int);
  // 정수 값으로 하나 더 추가
  public abstract void addIntHeader(String, int);
  public abstract void setStatus(int);
  public abstract void setStatus(int, String);
  public abstract int getStatus();
  public abstract String getHeader(String);
  public abstract Collection getHeaders(String);
  public abstract Collection getHeaderNames();
}

구현

Container가 HttpServletRequerst와 HttpServletResponse를 구현

GenericServlet, ServletResponse, ServletRequest

서블릿 모델을 유연하게 디자인함
HTTP 가 아니더라도 다른 Protocal을 구현할 수 있음


6. doGet(), doPost()

그외 메소드

  • head, trace, option, put, delete, connect가 존재
  • connect만 제외하고 HttpServlet 클래스의 doXxx()로 매칭됨
    • connect는 http프로토콜과 관련없기 때문
Http Method 하는 일
GET url로 자원(파일)을 달라고 요청
POST Request body에 정보를 추가하여 요청 url로 정보를 달라고 요청
HEAD GET이 무엇을 리턴하든지 헤더 정보만 요청, Response body 정보가 없는 GET과 동일
TRACE 요청한 메시지의 loopback 테스트 요청, 서버쪽에서 무엇을 받았는지 알고 싶을 때
PUT 동봉한 body 정보를 요청한 url로 올림
DELETE 요청한 url에 있는 자원(파일)을 삭제
OPTIONS 요청한 url이 응답할 수 있는 HTTP 메소드가 무엇인지 요청
CONNECT 터널링 목적으로 연결 요청

멱등

동일한 작업을 지속적으로 수행할 수 있음
Get은 멱등 메소드 이므로 어떤 부작용 없이 여러번 수행가능
Post는 멱등 메소드가 아니므로 서버로 전달되는 몸체의 정보는 트랜젝션을 위한 것이면 되돌릴 수 없음

  • 멱등은 다양한 의미가 있지만 HTTP/Servlet 환경에서는 동일 요청은 서버에 어떤 잘못된 결과를 야기하지 않고 두 번 이상 이루어 질 수 있다는 의미
    • 동일 요청은 동일 응답을 가져야 한다는 의미는 아님
    • 동일 요청으로 어떤 부작용도 발생하지 말아야 한다는 의미가 아님

7. 응답

redirect

client상 작업 발생
요청을 완전히 다른 url로 방향 전환

  1. 브라우저 주소창 url 입력
  2. 서버/컨테이너 요청 전달
  3. 서블릿은 다른 url로 보내야 함을 확인
  4. response 객체의 sendRedirect() 메소드 호출 / 서블릿 업무 종료
  5. HTTP Response에 상태 코드 301 값 + 새로운 url 값 포함
  6. 브라우저는 301 확인 후 location 헤더 값 확인
  7. 새 url로 새로운 요청 (브라우저도 url이 변하므로 사용자도 앎)
  8. 새로 발생한 요청은 전 요청과 동일하나 요청 방향이 바뀜
  9. 서버는 요청을 확인하고 서비스
// 상대경로도 이동가능
// 매개변수로 String 객체를 받음
response.sendRedirect("www.dec7.me"); 

Response가 이미 기록되고 난 후에 sendRedirect() 메소드 호출시 illegalStateException 발생

request dispatch

server상 작업 발생
웹 어플리케이션에 있는 다른 컴포넌트(보통 jsp)에게 처리 위임

  1. 브라우저 주소창 url 입력
  2. 서버/컨테이너 요청 전달
  3. 서블릿은 웹 어플리케이션의 다른 컴포넌트 (JSP)가 처리해야함을 확인
  4. 서블릿은 특정 jsp에게 제어를 전달
  5. 브라우저는 응답을 전달 받음
    • 브라우저 url이 변하지 않음
    • 브라우저는 페이지를 jsp가 만드는지 servlet이 만드는지 알 수 없음
RequestDispatcher view = request.getRequestDispatcher("result.jsp");
view.forward(request, response);

Written with Dec7.