Servlet

ybong·2022년 2월 17일
0

Servlet이란?

Java Web Application

  • 작성된 서블릿은 WAS(tomcat)에 의해서 동작이 된다. 그 이후 웹 브라우저를 통해서 tomcat 서버에 요청을 보내고 브라우저에 응답을 받는 것.
  • WAS에 설치(deploy)되어 동작하는 어플리케이션
  • 앞서 만든 firstweb이 자바 웹 어플리케이션이다.
  • 자바 웹 어플리케이션에는 HTML, CSS, 이미지, 자바로 작성된 클래스(Servlet도 포함, package, 인터페이스 등), 각종 설정파일 등이 포함된다.
  • 우리가 사용하는 쇼핑몰, 카페 등이 모두 웹 어플리케이션이라 보면 된다.
  • 앞에서 만든 firstweb은 하나의 Servlet으로 구성된 간단한 웹 어플리케이션이라고 말할 수 있다.

Java 웹 어플리케이션의 폴더 구조

  • 자바 웹 어플리케이션은 WAS로 돌아가기 때문에 이 폴더 구조를 지켜줘야 한다.
  • 반드시 WEB-INF폴더가 있어야 한다.
    • web.xml 파일
      • 배포기술자, 이 웹 어플리케이션에 대한 정보를 다 갖고 있는 파일
      • servelt 3.0 미만에서는 필수이나, 그 이상에서는 어노테이션을 사용해서 반드시 필요한 것은 아니다.
    • lib 폴더
      • 각종 jar 파일들
    • classees 폴더
      • java 패키지, 실제 class들, 서블릿도 포함
  • 각종 폴더, 이미지, 다양한 리소스들, 프론트 파일들

*저 디렉토리 구조 보는 것 tree라는 명령어로 가능 → 리눅스에는 원래 없어서, brew로 설치하면 된다. brew install tree

Servlet이란?

  • 자바 웹 어플리케이션의 구성요소 중 동적인 처리를 하는 프로그램의 역할
    • 이미 응답할 페이지를 만들어서 갖고있는 것이 아니라, 요청이 들어왔을 때 서블릿이 실행되면서 응답할 코드를 만들어내고, 응답을 한다.
  • 서블릿을 정의해보면
    • WAS에서 동작하는 Java의 클래스다
    • HttpServlet 클래스를 상속받아야 한다
    • 서블릿괴 JSP로부터 최상의 결과를 얻으려면, 웹페이지를 개발할 때 이 두가지를 조화롭게 사용해야 한다.
      • 예: 웹 페이지를 구성하는 화면(HTML)은 JSP로 표현하고, 복잡한 프로그래밍은 서블릿으로 구현

Servlet 작성방법

버전에 따라 두가지 방법

  1. Servlet 3.0 spec 이상에서 사용하는 방법
    • web.xml 파일을 사용하지 않는다
    • 자바 어노테이션(annotation)을 사용한다
    • 앞에서 실습했던 first web에서 사용함
  2. Servlet 3.0 spec미만에서 사용하는 방법
    • servlet을 등록할 때 web.xml 파일에 등록한다

실습하며 메모

  • 서블릿 동적처리 : 이미 응답할 페이지를 만들어서 갖고있는 것이 아니라, 요청이 들어왔을 때 서블릿이 실행되면서 응답할 코드를 만들어내고, 응답을 한다.
  • HttpServletRequest: 요청객체
  • HttpServletResponse: 응답객체
    • setContentType(): 응답할 타입을 지정해주는 것
      • response.setContentType("text/html;charset=utf-8");
    • getWriter() 보낼 내용을 넣어주는 통로 만들어주기
    • fd같은 것 개념인 것 같다
      • return값: PrintWriter객체
      • PrintWriter out = response.getWriter();
        • print(): 그 fd에 (printwriter에)출력
        • close(): 사용 후 닫아줘야 한다.

Intellij에서 Dynamic web project 만들기

ref1

ref2

package dynamic_webapp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "TenServlet", value = "/ten")
public class TenServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("<h1>1-10까지 출력</h1>");
        for(int i=1; i <=10; i++) {
            out.print(i + "<br>");
        }
        out.close();
    }
}

(2.5ver 실습은 pass)

Servlet 라이프 사이클

라이프사이클?

  • 어떤 객체의 생성부터 소멸까지의 과정을 Life Cycle이라고 한다.

실습

  • LifecycleServlet 작성
  • HttpServlet의 3가지 메서드를 오버라이딩
    • init()
    • service(request, response) (HttpServletRequest/Respond)
    • destroy()

과정

  1. url을 통해 어떤 서블릿인 지 알아냄
  2. 해당 서블릿 클래스가 메모리에 존재하는 지 확인 → 없다면 생성 (Constructor called)
  3. 그 다음 init 호출
  4. 그 다음 service 호출
  5. 새로고침하거나 다시 요청했을 때, 다시 생성, init은 다시 되지 않고, service만 호출된다.
    • 메모리에 이미 존재하기 때문에
  6. destroy는 코드 내용이 바뀌거나 서버 종료될 때 호출됨

정리

  • 처음에 init이 호출, 그다음 service 호출, destroy는 웹 어플리케이션이 갱신되거나, WAS가 종료될 때 호출된다.
if (메모리에 없음) {
	해당 서블릿 클래스를 메모리에 올림
	init() 메서드 실행
}
service() 메서드 실행
  • 따라서, 요청이 왔을때 응답하는 내용들은 service에 들어가야함! (항상 실행되니까)

service(request, respond) 메서드

  • service 메서드는 HttpServlet의 service메서드가 구현 되어있는 상태.
  • service 오버라이딩 하지 않으면, 부모클래스의 service가 실행된다.
  • HttpServlet의 service메서드는 템플릿 메서드 패턴으로 구현되어있다.
    • 클라이언트 요청이 GET일 경우, 자신이 갖고 있는 doGet(request, response)메서드를 호출
    • 클라이언트 요청이 POST일 경우, 자신이 갖고 있는 doPost(request, response)를 호출
  • 그렇기 때문에 doGet, doPost만 오버라이딩 하고 service 오버라이딩 하지 않더라도 잘 작동 된다.
package example.firstweb;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "LifecycleServlet", value = "/LifecycleServlet")
public class LifecycleServlet extends HttpServlet {

    public LifecycleServlet() {
        System.out.println("LifecycleServlet 생성!");
    }

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

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

//    @Override
//    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        System.out.println("service 호출");
//    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>form</title></head>");
        out.println("<body>");
        out.println("<form method='post' action='/firstweb/LifecycleServlet'>"); //요청이 들어왔을 때, 해당 URL로 POST메서드 호출
        out.println("name : <input type='text' name='name'><br>");
        out.println("<input type='submit' value='ok'><br>");
        out.println("</form>");
        out.println("</body>");
        out.println("</html>");
        out.close();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        String name = request.getParameter("name");
        out.println("<h1> hello " + name + "</h1>");
        out.close();
    }
}
  • 같은 URL 주소지만 GET방식이냐, POST방식이냐에 따라 다른 메서드가 호출된다.

Request, Response 객체 이해하기

웹의 동작 과정

  1. 웹 브라우저에 URL을 입력하고 엔터를 치면, 웹 브라우저는 도메인과 포트번호를 이용해서 서버에 접속한다.
  2. 그리고 나서 path정보, 클라이언트 ip 등 다양한 정보를 포함한 요청정보를 서버에게 전송한다
  3. WAS는 웹 브라우저로부터 Servlet 요청을 받으면,
    • 요청할 때 가지고 있는 정보를 HttpServletRequest 객체를 생성하여 저장
    • 웹브라우저에게 응댑을 보낼 때 사용하기 위한 HttpServletResponse 객체 생성
    • 생성된 HttpServletRequest, HttpServletResponse객체를 요청정보에 있는 path에 매핑 된 서블릿에게 전달
    • 이렇게 전달한 객체는 service, doGet, doPost같은 메서드의 인자로 전달되어 사용된다.

Request, Response 객체

HttpServletRequest

  • 클라이언트가 서버에게 보낸 요청을 추상화한 객체
  • http 프로토콜의 request 정보를 서블릿에게 전달하기 위한 목적으로 사용
  • 요청할 때 가지고 있는 정보를 모두 메서드로 담는다.
    • 헤더정보, 파라미터, 쿠키, URI, URL 등의 정보를 읽어들이는 메서드를 갖고 있다.
    • 심지어 요청한 사용자가 어떤 언어를 사용하고 있느냐까지
  • Body의 Stream을 읽어들이는 메서드를 갖고 있다.

HttpServletResponse

  • 서버가 클라이언트에게 응답하기 위한 정보를 추상화한 객체
  • WAS는 어떤 클라이언트가 요청을 보냈는 지 알고 있고, 해당 클라이언트에 응답을 보내기 위한 HttpServletResponse객체를 생성하여 서블릿에 전달
  • 서블릿은 해당 객체를 이용하여 content type, 응답코드, 응답메시지 등을 전송

요청 정보 확인 실습

  • 클라이언트가 서버에게 요청을 보낼 때 많은 정보를 갖고 요청을 하는데, 이 때 요청 정보들이 뭐가 있는 지 실습해보자.

헤더 정보 읽어들이기

  • 웹 브라우저가 요청정보에 담아서 보내는 header값을 읽어들여 브라우저 화면에 출력한다.
package example.firstweb;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

@WebServlet(name = "HeaderServlet", value = "/header")
public class HeaderServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter(); //클라이언트와의 연결통로 하나 생성
        out.println("<html>");
        out.println("<head><title>form</title></head>");
        ((PrintWriter) out).println("<body>");

        //Enumeration: 문자열
        Enumeration<String> headerNames = request.getHeaderNames(); // 요청객체를 통해 헤더 이름을 받아온다.
        while(headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            String headerValue = request.getHeader(headerName); // 헤더의 값 정보를 알아낼 수 있다.
            out.println(headerName + " : " + headerValue + " <br> "); // 헤더의 이름과 값을 PrintWriter에 쓴다.
        }

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

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}
host : localhost:8080
connection : keep-alive
sec-ch-ua : " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile : ?0
sec-ch-ua-platform : "macOS"
upgrade-insecure-requests : 1
user-agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36
accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
sec-fetch-site : same-origin
sec-fetch-mode : navigate
sec-fetch-user : ?1
sec-fetch-dest : document
referer : http://localhost:8080/
accept-encoding : gzip, deflate, br
accept-language : en-US,en;q=0.9,ko-KR;q=0.8,ko;q=0.7
cookie : Idea-2951d09e=6ec0a767-d804-48b7-95e9-300b97f0ef28; JSESSIONID=B919BDF2A6141830EFF447FD237971A9

파라미터 읽어들이기

  • URL주소의 파라미터 정보를 읽어 들여 브라우저 화면에 출력한다.
  • 파라미터란?
    • [http://localhost:8080/firstweb/param?name=kim&age=5](http://localhost:8080/firstweb/param?name=kim&age=5)
    • 여기서 ? 뒤에 있는 부분
    • & 를 기준으로 파라미터가 나눠진다.
    • {파라미터이름}={파라미터값}
  • 파라미터들은 URL을 통해서만 전달되는 것은 아니고, html form태그라는 게 존재하는데, 이 태그 안에 input이라는 태그를 사용하여 파라미터를 넣어주고 꺼낼 수 있다.

그 외의 요청정보 출력

  • URI, URL, PATH, Remote host 등에 대한 정보 출력
  • http://localhost:8080/firstweb/info
  • request.get~ 여러 정보를 가져오는 메서드가 존재한다.
uri : /firstweb/info  //포트번호 이하의 값들
url : http://localhost:8080/firstweb/info //전체주소
contentPath : /firstweb //Application context 웹 어플리케이션과 매핑된 패스
remoteAddr : 0:0:0:0:0:0:0:1 //클라이언트의 주소값 (로컬컴퓨터라 이럼, 다른경우 IP)
profile
study blog

0개의 댓글