본문 바로가기
4. Backend Development/1. Spring Framework

5. Servlet

by H232C 2020. 9. 1.

1. 서블릿 (Servlet)
자바 엔터프라이즈 에디션은 웹 애플리케이션 개발용 스팩과 API 제공.
요청 당 쓰레드 (만들거나, 풀에서 가져다가 ) 사용 (프로세스가 떠서 쓰레드로 처리함)
그 중에 가장 중요한 클래스중 하나가 HttpServlet.

2. 서블릿 등장 이전에 사용하던 기술인 CGI (Common Gateway Interface)
요청 당 프로세스를 만들어 사용

3. 서블릿의 장점 (CGI에 비해)
빠르다.
플랫폼 독립적
보안
이식성

4. 서블릿 엔진 또는 서블릿 컨테이너 (톰캣, 제티, 언더토, ...)
세션 관리
네트워크 서비스
MIME 기반 메시지 인코딩 디코딩
서블릿 생명주기 관리

5. 서블릿 생명주기
서블릿 컨테이너가 서블릿 인스턴스의 init() 메소드를 호출하여 초기화 한다.
최초 요청을 받았을 때 한번 초기화 하고 나면 그 다음 요청부터는 이 과정을 생략한다.
서블릿이 초기화 된 다음부터 클라이언트의 요청을 처리할 수 있다.
각 요청은 별도의 쓰레드로 처리하고 이때 서블릿 인스턴스의 service() 메소드를 호출한다.
이 안에서 HTTP 요청을 받고 클라이언트로 보낼 HTTP 응답을 만든다.
○ service()는 보통 HTTP Method에 따라 doGet(), doPost() 등으로 처리를 위임한다.
따라서 보통 doGet() 또는 doPost()를 구현한다.
서블릿 컨테이너 판단에 따라 해당 서블릿을 메모리에서 내려야 할 시점에 destroy()를 호출한다.

 

6. 서블릿 구축
 - 메이블 프로젝트 생성 (archetype-webapp)

 - pom.xml 추가 (서블릿 API)

- 서블릿을 테스트할 톰캣 구성

 -Duser.language=en -Duser.region=us (톰캣 로그 한글 깨짐 방지)
 - Build exploded artifact 설정 (war를 외부에서 말아서 실행하겠다.)

 

- webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

 

- src/main/java/servlet/HelloServlet (java 디렉토리는 java 디렉토리 지정해줘야 함)

package servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println("init");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("doGet");
        resp.getWriter().println("<html>");
        resp.getWriter().println("<head>");
        resp.getWriter().println("<body>");
        resp.getWriter().println("<h1>Hello</h1>");
        resp.getWriter().println("</body>");
        resp.getWriter().println("</head>");
        resp.getWriter().println("</html>");

    }

    @Override
    public void destroy() {
        super.destroy();
    }
}

 

- hello 요청화면

 

- Servlet 동작 로그(Hello 요청시 Init으로 프로세스 생성, doGet 호출, 이후 요청은 쓰레드로 응답, 서버 종료시 Destroy 발생)

 

7. Listener 등록 (Listenr : 서블릿 초기화, 종료시 작업을 추가하여 수행할 수 있음)

- web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  
  <listener>
    <listener-class>servlet.MyListener</listener-class>
  </listener>

    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

- MyListener.java (서블릿 컨텍스트 초기화 및 종료시 상황에 맞는 메서드 실행)

package servlet;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Context Initialized");
        sce.getServletContext().setAttribute("name", "h232ch");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Context Destroyed");

    }
}

 

8. Servlet Filter (특정 서블릿에 필터를 적용하여 기능 추가 및 실행)

- web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>servlet.MyFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <servlet-name>hello</servlet-name>
  </filter-mapping>

  <listener>
    <listener-class>servlet.MyListener</listener-class>
  </listener>

    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>

    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

 

- myFilter.java

package servlet;

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

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter Init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter");
        filterChain.doFilter(servletRequest,servletResponse); // 요청 응답을 필터 체인으로 연결을 해줘야 함 (마지막 필터는 서블릿에 연결됨)
    }

    @Override
    public void destroy() {
        System.out.println("Filter Destroy");
    }
}

 

- Servlet Filter 적용 화면

 

9. 스프링 IoC 적용

- web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>servlet.AppConfig</param-value>
  </context-param>

  <!--  Spring IoC 컨테이너를 리스너가 적용하는데 적용시 Spring IoC 컨테이너는 Context-param을 참조하여 생성된다. -->
  <!--  servlet.AppConfig 파일의 설정을 참조하여 생성 -->

  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>servlet.MyFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <servlet-name>hello</servlet-name>
  </filter-mapping>

<!--  <listener>-->
<!--    <listener-class>servlet.MyListener</listener-class>-->
<!--  </listener>-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
<!--  Spring IoC 컨테이너를 서블릿 애플리케이션의 생명주기에 맞추어 바인딩 해주는 코드 -->
<!--  서블릿 초기화시 Spring IoC 컨테이너를 연동해주고 종료시 연동을 종료 시켜줌 -->


    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>



    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

 

- AppConfig.java (ComponentScan -> @Service, @Component.. 등 어노테이션 이붙은 클래스를 빈으로 등록)

package servlet;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {
}

 

- HelloService.java

package servlet;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
    public String getName(){
        return "h232ch";
    }
}

 

- HelloServlet.java

package servlet;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println("init");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("doGet");

        ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
//        서블릿 컨텍스트에서 getAttribute를 이용하여 WebApplicationContext를 가져온뒤 context에 담는다.

        HelloService helloService = context.getBean(HelloService.class);
//        context에서 getBean을 이용하여 HelloService를 불러와서 helloService에 지정해준다.

        resp.getWriter().println("<html>");
        resp.getWriter().println("<head>");
        resp.getWriter().println("<body>");
        resp.getWriter().println("<h1>Hello"+ helloService.getName() +"</h1>");
//        context를 이용하여 가져온 빈의 메서드를 이용하여 이름을 호출한다.
//        스프링이 제공해주는 IoC 컨테이너에서 가져온 빈이라는 게 중요함
        resp.getWriter().println("</body>");
        resp.getWriter().println("</head>");
        resp.getWriter().println("</html>");

    }

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

 

 

'4. Backend Development > 1. Spring Framework' 카테고리의 다른 글

7. Spring boot  (0) 2020.09.24
6. DispatcherServlet  (0) 2020.09.01
4. MacOS Security Management System  (0) 2020.07.21
3. Spring Framework 기반 웹 프로젝트  (0) 2020.06.09
2. Spring IoC Container  (0) 2020.04.30

댓글