서블릿

Seunghee Lee·2023년 5월 24일
0

Spring MVC

목록 보기
2/3

⚠️ Spring Boot 는 사실 서블릿과 관련이 없다. 그러나 Spring Boot 는 톰캣 서버를 내장하고 있기 때문에 별도의 서버 설치 없이 편리하게 서블릿 코드를 실행할 수 있다.
→ 따라서 실습은 Spring Boot 에서 실행하고자 한다.


🌐 서블릿

💡 @ServletComponentScan = 스프링에서 서블릿 서버를 쓰기 위함

서블릿을 사용하기 위해선 HttpServlet 을 상속받아야 한다.

💡 @WebServlet() 을 지정한다.

  • name = "" : 서블릿 이름 (서블릿 이름은 겹치면 안된다.)
  • urlPatterns = "url" : url이 실행된다.
@WebServlet()
public class HelloServlet extends HttpServlet {}

🎲 @Override 메소드 보기 : ctrl + o
protected 타입의 서비스 메소드를 호출한다.


💡 HttpServletRequest, HttpServletResponse 는 interface 로 정의되어 있다.

톰캣이나 Jetty 와 같은 WAS 서버들이 서블릿 표준 서버를 구현한다.
→ 이 구현체를 찍으면 다음과 같다.


쿼리파라미터 넘기기 = http://localhost:8080/hello?username=kim


📗 서블릿 컨테이너 동작 방식

✅ 내장 톰캣 서버 생성

  1. 스프링 부트 실행하면 → 내장 톰캣 서버를 띄워준다.
  2. 서블릿 컨테이너를 통해서 서블릿을 생성한다.

💡 HTTP 에서 요청을 하면, 서버에 응답 메세지가 찍힌다.


✅ 웹 애플리케이션 서버의 요청 응답 구조

  1. 웹 브라우저로부터 요청이 들어오면 HTTP 요청 메시지를 기반으로 request, response 가 생성된다.
  2. 서블릿 컨테이너에서 request, response 가 실행되고,
  3. 필요한 작업 후 서블릿이 종료하면서 response 정보를 가지고 HTTP 응답을 생성한다. 위와 같은 HTTP 응답 형태로 생성된다.

🌐 HttpServletRequest 개요

📗 HttpServletRequest 역할

  • 서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신 HTTP 요청 메시지를 파싱한다.
  • 파싱한 결과를 HttpServletRequest 객체에 담아서 제공한다.

✅ HTTP 요청 메시지 형태

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

💡 HttpServletRequest 객체는 추가로 여러가지 부가 기능도 함께 제공한다.

✅ 임시 저장소 기능

  • 요청 메시지가 오고 응답 메시지가 나갈 때까지 유지되는 임시 저장소 기능
    - 저장: request.setAttribute(name, value)
    - 조회: request.getAttribute(name)

※ MVC Pattern 에서 많이 사용된다.

✅ 세션 관리 기능

  • request.getSession(create: true)
  • 로그인 할 때, 사용된다.

🌐 HttpServletRequest 사용

🎲 변수 생성: ctrl + alt + v


✅ START LINE 출력해보자

→ QueryString 이 없기 때문에 null 값으로 출력된다.

💡 만약 쿼리를 지정했다면 다음과 같이 출력된다.


✅ Header 정보를 출력해 보자

  • request.getHeaderNames() : 헤더의 모든 정보를 출력할 수 있다.
  • 헤더에서 꺼내는 정보가 많은 이유는 ?
    웹 브라우저가 요청할 때 기본적으로 이것들을 보내기 때문 !

✅ Header의 편의 정보만을 조회해 보자

  • request.getLocales() : 헤더의 Locales 의 모든 정보를 꺼내올 수 있다.
  • request.getCookies() : 쿠키 정보는 http header에 담긴다.
  • request.getHeader(): Header 딱 하나 만의 정보를 꺼낼 수 있다.

🌐 HTTP 요청 데이터 개요

클라이언트에서 서버로 데이터를 전달하는 방법은 주로 다음과 같은 3가지 방법이 사용된다.

✅ GET - 쿼리 파라미터

  • /url ?username="?username=hello&age=20"
    : ""에 쿼리 파라미터를 작성하여 넘겨준다.
  • http body 에 데이터를 보내지 않고, URL 에 쿼리 파라미터를 포함해서 넘기는 방식이다.
  • 검색하거나 필터링, 페이징 등에서 주로 사용한다.

✅ POST - HTML Form

  • Content type : application/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파라미터 형식으로 전달 ex) username=hello&age=20
  • 회원 가입 이나 주문 등에서 주로 사용된다.

✅ HTTP Message Body 에 데이터를 직접 담아서 요청

  • HTTP API 에서 주로 사용한다. (JSON / XML / TEXT 담아서 클라이언트에게 전달한다.)
  • 데이터 형식은 주로 JSON 을 사용한다.
  • POST / PUT / PATCH 사용이 가능하다.

📗 GET 쿼리 파라미터

메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하는 방식

💡 쿼리 파라미터는 URL에 다음과 같이 ? 를 시작으로 보낼 수 있다.

  • 추가 파라미터는 & 로 구분하면 된다.
    ex) http://localhost:8080/request-param?username=hello&age=20

        //paramName = 키(key)  ->  username, age
        //request.getParameter = 값(value)  ->  hello, 20
        request.getParameterNames().asIterator()
                        .forEachRemaining(paramName -> System.out.println(paramName + " = " + request.getParameter(paramName)));

🤔 파라미터 이름은 하나인데, 값이 중복되면 어떻게 될까 ?

🅰️ request.getParameter() 는 하나의 파라미터에 대해서 단 하나의 값만 있을 때 사용해야 한다. 만약 중복일 때에는 request.getParameterValues() 를 사용해야 한다.


📗 POST HTML Form

HTML 의 Form 을 사용해서 클라이언트에서 서버로 데이터를 전송하는 방식

💡 POST 의 HTML Form 을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다.

  • 요청 URL : http://localhost:8080/request-param
  • content-type : application/x-www-form-urlencoded
  • message body : username=hello&age=20

💡 application/x-www-form-urlencoded 형식은 앞서 GET 에서 살펴본 쿼리 파라미터 형식과 같다. → 따라서 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다.

  • 클라이언트(웹 브라우저) 입장에서는 두 방식에 차이가 있지만,
  • 서버 입장에서는 둘의 형식이 동일하므로 → request.getParameter() 로 편리하게 구분없이 조회할 수 있다.

정리하면
request.getParameter() 는 GET URL 쿼리 파라미터 형식도 지원하고 + POST HTML Form 형식도 지원하다.


💡 POST 는 content-type 을 필수로 지정해 줘야 한다.

🤔 그렇다면 테스트 할 때마다 Form 을 만들어야 하나 ? → No ! 우리에겐 Postman 이 있다.

  • Postman 테스트 할 때,
    - Body 는 x-www-form-urlencoded 선택
    - 헤더에서 content-type : application/x-www-form-urlencoded 로 지정된 부분 꼭 확인하기 !

📗 API 메시지 바디 - 단순 텍스트

이제부터는 HTTP API 나 REST API 를 사용해서 HTTP 메시지 바디에 데이터를 직접 담아서 요청하는 형태로 진행해보자 !

  • inpustStream() : 메시지 바디의 내용을 byte 코드로 반환한다.
  • StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8)
    : inputstream 내용을 string 으로 변환한다.
    ※ 이때 UTF_8 와 같이 인코딩 타입을 작성해 줘야 한다.


📗 API 메시지 바디 - JSON

JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson 과 같은 JSON 변환 라이브러리 를 추가해서 사용해야 한다.

스프링 부트로 Spring MVC 를 선택하면 기본으로 Jackson 라이브러리 (ObjcetMapper) 를 제공한다.


🌐 HttpServletResponse - 기본 사용법

📗 HttpServletResponse 의 역할

  • HTTP 응답 메시지 생성: HTTP 응답코드 지정 / 헤더 & 바디 생성
  • 편의 기능 제공: Content-type / 쿠키 / Redirect

response.setHeader(); 로 직접 헤더를 설정하는 것보다 Servlet 에서 제공하는 편의 기능을 사용하여 설정하는 것이 더 좋다 !


💡 Content 메서드

response.setHeader(); 로 직접 헤더를 설정하는 것보다
response.setContType(), response.setCharacterEncoding 로 설정하자.

private void content(HttpServletResponse response) {
	//Content-type: text/plain;charset=utf-8
    	
    //Good 👍
	response.setContentType("text/plain");
 	response.setCharacterEncoding("utf-8");
    
	//Bad 👎
	response.setHeader("Content-Type", "text/plain;charset=utf-8");
}

response.setHeader(); 로 직접 헤더를 설정하는 것보다
서블릿에서 제공하는 Cookie 클래스를 사용하는 것이 보다 편리하고 가독성이 좋다.

private void cookie(HttpServletResponse response) {
	//Set-Cookie: myCookie=good;
    
    //Good 👍
    Cookie cookie = new Cookie("myCookie", "good");	
 	cookie.setMaxAge(600); //600초
 	response.addCookie(cookie);
    
    //Bad 👎
    response.setHeader("Set-Cookie", "myCookie=good; Max-Age=600");
}

💡 Redirect 메서드

response.setHeader(); 로 직접 헤더를 설정하는 것보다
response.setContType(), response.setCharacterEncoding 로 설정하자.

private void redirect(HttpServletResponse response) throws IOException {
	//Status Code 302
    //Location: /basic/hello-form.html
	
    //Good 👍
	response.sendRedirect("/basic/hello-form.html");
	
    //Bad 👎
    response.setStatus(HttpServletResponse.SC_FOUND); //302
 	response.setHeader("Location", "/basic/hello-form.html");
}

📗 단순 텍스트, HTML

HTML 내용을 Java 에서 구현할 때, PrintWriter 를 사용해서 보여줄 수 있다.

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Content-type: 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>Hello!</div>");
        writer.println("</body>");
        writer.println("</html>");
}

localhost:8080/response-html 로 들어가면 Hello! 가 찍힌 걸 볼 수 있다.

실제 소스 코드는 다음과 같다.


📗 API JSON

→ 가장 많이 사용하는 방식 !

※ 스프링MVC 쓰면 사실 완전 단축되는 데 일단은 차근차근 알아가 보자 :)

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("Lee");
        helloData.setAge(24);

        //{"username":"Lee", "age":24}
        String result = objectMapper.writeValueAsString(helloData);   //객체를 받아서 String 으로 변환
        response.getWriter().write(result);
}

⚠️ application/json 스펙 상 utf-8 을 기본으로 사용하도록 정의되어 있다. 따라서 사실 위 코드와 같이 인코딩 타입을 정의하는 것은 의미 없기 때문에 굳이 안 써도 된다.

profile
자라나라 개발개발 ~..₩

0개의 댓글