IT recording...

[스프링 MVC1] 2. 서블릿 본문

Spring

[스프링 MVC1] 2. 서블릿

I-one 2022. 1. 14. 11:22

원문 링크

https://adorable-aspen-d23.notion.site/MVC1-2-b1a5d20371de45a5a22787c30c3064f5

 

[스프링 MVC1] 2. 서블릿

1. 서블릿

adorable-aspen-d23.notion.site

김영한님의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술] 강의를 듣고 작성한 글입니다.

1. 서블릿

: 동적 웹 페이지를 만들 때 사용되는 자바 기반의 웹 어플리케이션 프로그래밍 기술

  • 요청(request)와 응답(response)를 간단한 메서드 호출만으로 다룰 수 있게 해주는 기술
  • 웹 서버에서 서블릿 인스턴스를 생성 후 서버에서 실행되다가, 웹 브라우저에서 서버에 요청을 하면 동작을 수행하고 웹 브라우저에 응답하는 방식으로 작동한다.

특징

  • 클라이언트의 request에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트
  • html을 이용하여 response한다
  • 쓰레드를 이용한다.

서블릿 컨테이너

: 서블릿을 담고 관리해주는 컨테이너

  • HttpServletRequest, HttpServletResponse 두 객체를 생성하여 동적인 페이지 생성 후 응답을 보낸다.
  • HttpServletRequest
    • http프로토콜의 request정보를 servlet에게 전달하기 위한 목적
    • 헤더 정보, 파라미터, 쿠키, URI, URL등의 정보를 읽어 들이는 메서드와 Body의 Stream을 읽어 들이는 메서드
  • HttpServletResponse
    • WAS가 클라이언트에게 응답을 보내기 위해 이 객체를 생성하여 서블릿에게 전달하고, content type, 응답코드, 응답 메시지 등을 전송한다.
  • 주요 기능
    • 생명주기 관리
      • 서블릿의 생명주기를 관리한다. 서블릿 컨테이너가 기동 되는 순간 서블릿 클래스를 로딩해서 인스턴스화하고, 초기화 메서드를 호출하고, 요청이 들어오면 적절한 서블릿 메서드를 찾아 동작한다.
      • 서블릿의 생명이 다하는 순간 가비지 컬렉션을 통해 메모리에서 제거한다.
    • 통신 지원
      • 소켓을 생성하고, 특정 포트를 리스닝하고, 연결 요청이 들어오면 스트림을 생성해서 요청을 받는 과정을 통해 통신을 수행해야하는데,
      • 서블릿 컨테이너가 이를 대신 해준다.
      • 개발자가 비즈니스 로직에 더 집중할 수 있다.
    • 멀티스레딩 관리
      • 동시에 여러 요청이 들어와도 멀티스레딩을 이용하여 동시다발적인 작업을 관리할 수 있다.
    • 선언적인 보안관리
      • 서블릿 컨테이너는 보안 관련 기능을 지원하기 때문에, 서블릿 또는 자바 클래스 안에 보안 관련된 메서드를 구현하지 않아도 된다.

참고

https://coding-factory.tistory.com/742

2. HttpServletRequest

POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20

기능

  • Start line
    • HTTP 메소드
    • URL
    • 쿼리 스트링
    • 스키마, 프로토콜
  • 헤더
  • 바디
    • form 파라미터 형식 조회
    • message body 데이터 직접 조회

* HTTP 요청 데이터

  1. GET - 쿼리 파라미터
    • /url?username=hello&age=20
    • 메시지 바디 없이 쿼리 파라미터에 데이터를 포함해서 전달
    • 검색,필터,페이징 등에서 많이 사용
  2. POST - HTML Form
    • content-type:application/x-www-form-urlencoded
    • 메시지 바디에 쿼리 파라미터 형식으로 전달 username=hello&age=20
    • 회원가입,상품주문,HTML Form 사용
  3. HTTP message body에 직접 데이터 담아 요청
    • HTTP API에서 사용, JSON, XML, TEXT
    • 주로 JSON사용 (POST,PUT,PATCH)

2-1) HTTP request - GET 쿼리 파라미터

<http://localhost:8080/request-param?username=hello&age=20>
@WebServlet(name = "requestparamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("[전체 파라미터 조회 - start]");

        **request.getParameterNames().asIterator()
                .forEachRemaining**(paramName -> System.out.println(paramName + "=" + request.getParameter(paramName)));

        System.out.println("[전체 파라미터 조회 - end]");
        System.out.println();

        System.out.println("[단일 파라미터 조회 - start]");
        String username = **request.getParameter**("username");
        String age = request.getParameter("age");
        System.out.println("age = " + age);
        System.out.println("username = " + username);
        System.out.println("[단일 파라미터 조회 - end]");
    }
}
[전체 파라미터 조회] - start
username=hello
age=20
[전체 파라미터 조회] - end
[단일 파라미터 조회] request.getParameter(username) = hello request.getParameter(age) = 20
[이름이 같은 복수 파라미터 조회] request.getParameterValues(username) username=hello
username=kim

2-2) HTTP request - POST HTML Form

<http://localhost:8080/basic/hello-form.html>

요청 url : <http://localhost:8080/request-param>
content-type : application/x-www-form-urlencoded
message body : username=hello&age=20
  • 쿼리 파라미터 조회 형식과 같기 때문에 /request-param을 그대로 사용하면 된다.

2-3) HTTP request - API 메시지 바디 - 단순 text

POST <http://localhost:8080/request-body-string>
@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        **ServletInputStream inputStream = request.getInputStream();** //메시지 바디가 byte값으로 읽어와짐
        String messageBody = **StreamUtils.copyToString**(inputStream, StandardCharsets.UTF_8);//바이트를 String으로
        System.out.println("messageBody = " + messageBody);

        response.getWriter().write("ok");
    }
}

2-4) HTTP request - API 메시지 바디 - JSON

POST <http://localhost:8080/request-body-json>

content-type: application/json
message body: {"username": "hello", "age": 20} 
결과: messageBody = {"username": "hello", "age": 20}
@Getter
@Setter
public class HelloData {
    private String username;
    private int age;
}
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {

    **private ObjectMapper objectMapper = new ObjectMapper();**

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        System.out.println("messageBody = " + messageBody);

        HelloData helloData = **objectMapper.readValue**(messageBody, HelloData.class);//기본으로 제공하는 objectMapper를 통해 json을 객체로 바로 매핑
        System.out.println("helloData.getUsername() = " + **helloData.getUsername()**);
        System.out.println("helloData.getAge() = " + **helloData.getAge()**);

        response.getWriter().write("ok");
    }
}

3. HttpServletResponse

  • 기능
    • HTTP 응답코드 지정
    • 헤더 생성
    • 바디 생성
      • content-type, 쿠키, redirect

3-1) HTTP response

@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       **//[status-line]
        response.setStatus(HttpServletResponse.SC_OK);

        //[response-headers]
        response.setHeader("Content-Type","text/plain;charset=utf-8");
        response.setHeader("Cache-Control","no-cache,no-store,must-revalidate");
        response.setHeader("Pragma","no-cache");
        response.setHeader("my-header","hello");**

				//[Header 편의 메서드] 
				content(response); 
				cookie(response); 
				redirect(response);

        //[message body]
        PrintWriter writer = response.getWriter();
        writer.println("ok");
    }
}
  • content 편의 메서드
private void content(HttpServletResponse response) {
			//Content-Type: text/plain;charset=utf-8
			//Content-Length: 2
			//response.setHeader("Content-Type", "text/plain;charset=utf-8"); 
			response.setContentType("text/plain"); 
			response.setCharacterEncoding("utf-8"); 
			//response.setContentLength(2); //(생략시 자동 생성)
}
  • 쿠키 편의 메서드
private void cookie(HttpServletResponse response) {
			//Set-Cookie: myCookie=good; Max-Age=600; 
			//response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600"); 
			Cookie cookie = new Cookie("myCookie", "good"); 
			cookie.setMaxAge(600); //600초
      response.addCookie(cookie);
  }
  • redirect 편의 메서드
private void redirect(HttpServletResponse response) throws IOException {
      //Status Code 302
      //Location: /basic/hello-form.html
      //response.setStatus(HttpServletResponse.SC_FOUND); //302
      //response.setHeader("Location", "/basic/hello-form.html");
      response.sendRedirect("/basic/hello-form.html");
}

3-2) HTTP response - 단순 텍스트, HTML

  • 단순 텍스트
writer.println("ok");
  • HTML
<http://localhost:8080/response-html>
@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //contentType:text/html;charset=utf-8
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");

        PrintWriter writer = response.getWriter();
        writer.println("<html>");
        writer.println("<body>");
        writer.println("  <div>안녕?</div>");
        writer.println("</body>");
        writer.println("</html>");
    } 
}

3-3) HTTP response - JSON

<http://localhost:8080/response-json>
@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {

    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Content-Type:application/json
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

        HelloData helloData = new HelloData();
        helloData.setUsername("kim");
        helloData.setAge(20);

        //{"username":"kim","age":20}
        String result = objectMapper.writeValueAsString(helloData);
        response.getWriter().write(result);
    }
}
Comments