본문 바로가기
Spring MVC

[MVC] 서블릿(3)

by 개발 Blog 2024. 10. 14.

공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.

 

HTTP 요청 데이터 - 개요

HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자.

 

주로 다음 3가지 방법을 사용한다.

 

1. GET - 쿼리 파라미터

  •  /url?username=hello&age=20
  • 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달한다.
  • 검색, 필터, 페이징 등의 요청에서 주로 사용하는 방식이다.

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 등의 데이터를 직접 담아서 요청할 수 있다.
  • POST, PUT, PATCH 메서드에서 주로 사용되며, 데이터 형식으로는 주로 JSON을 사용한다.

4. POST - HTML Form 예시

  • 사용자가 폼에 입력한 데이터를 서버에 전송하기 위한 방법이다.
  • 아래 예시는 username과 age라는 값을 서버로 POST 요청을 통해 전송하는 과정이다.

위 예시는 클라이언트에서 서버로 POST 요청을 통해 데이터를 전송하는 과정을 나타내며, 서버는 해당 요청을 받아 데이터를 처리하게 된다.

 

HTTP 요청 데이터 - GET 쿼리 파라미터

클라이언트에서 서버로 데이터를 전송하는 방법 중 하나는 GET 쿼리 파라미터를 사용하는 것이다. 메시지 바디 없이 URL에 데이터를 포함하여 전달하며, 검색, 필터링, 페이징과 같은 상황에서 주로 사용된다.

 

전달 데이터 예시

username=hello
age=20

 

쿼리 파라미터 전송 방식

쿼리 파라미터는 URL에 ? 를 시작으로 데이터를 전달하며, 추가 파라미터는 &로 구분한다.

http://localhost:8080/request-param?username=hello&age=20

 

서버에서 쿼리 파라미터 조회 방법

서버에서는 HttpServletRequest 객체가 제공하는 메서드를 통해 쿼리 파라미터를 조회할 수 있다.

 

쿼리 파라미터 조회 메서드

String username = request.getParameter("username"); //단일 파라미터 조회
Enumeration<String> parameterNames = request.getParameterNames(); //파라미터 이름들 모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map으로 조회
String[] usernames = request.getParameterValues("username"); //복수 파라미터 조회

 

예시 서블릿 코드

package hello.servlet.basic.request;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Enumeration;

/**
 * 1. 파라미터 전송 기능
 * http://localhost:8080/request-param?username=hello&age=20&username=kim&age=30
 */
@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("[단일 파라미터 조회]]");
        String username = request.getParameter("username");
        String age = request.getParameter("age");

        System.out.println("username = " + username);
        System.out.println("age = " + age);

        System.out.println("[이름이 같은 복수 파라미터 조회]");
        String[] usernames = request.getParameterValues("username");
        for (String name : usernames) {
            System.out.println("username = " + name);
        }
        response.getWriter().write("ok");
    }
}

 

복수 파라미터에서 단일 파라미터 조회

username=hello&username=kim처럼 파라미터 이름은 같고 값이 여러 개일 때 request.getParameter()는 첫 번째 값을 반환한다. 이런 상황에서는 request.getParameterValues()를 사용하여 모든 값을 배열로 받아야 한다.

String[] usernames = request.getParameterValues("username");
for (String name : usernames) {
    System.out.println("username = " + name);
}

이를 통해 클라이언트가 전달한 모든 파라미터 값을 처리할 수 있다.

 

HTTP 요청 데이터 - POST HTML Form

이번에는 HTML의 Form을 사용하여 클라이언트에서 서버로 데이터를 전송하는 방법을 알아보자. 이 방식은 주로 회원 가입이나 상품 주문 같은 데이터 전송에 사용된다.

 

특징

  • Content-Type: application/x-www-form-urlencoded
  • 메시지 바디에 쿼리 파라미터 형식으로 데이터를 전달한다.
    • 예시: username=hello&age=20

예시 HTML Form

src/main/webapp/basic/hello-form.html 파일을 생성하여 다음과 같이 작성한다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Form Example</title>
</head>
<body>
    <form action="/request-param" method="post">
        username: <input type="text" name="username" />
        age: <input type="text" name="age" />
        <button type="submit">전송</button>
    </form>
</body>
</html>

 

실행해 보자

http://localhost:8080/basic/hello-form.html에 접속하여 HTML Form을 사용해 데이터를 POST 방식으로 전송할 수 있다.

주의사항

웹 브라우저가 결과를 캐시 할 수 있기 때문에, 과거에 작성했던 HTML 결과가 보이는 경우가 있다. 이런 경우에는 웹 브라우저의 새로 고침 버튼을 눌러서 최신 내용을 불러와야 한다. 또한, 서버를 재시작하지 않은 경우에도 예전 결과가 나올 수 있다.

 

POST HTML Form 전송 시 브라우저가 만드는 HTTP 메시지 형식

웹 브라우저에서 POST 방식으로 HTML Form을 전송하면 다음과 같은 형식으로 HTTP 메시지가 생성된다. 이는 브라우저의 개발자 도구에서 확인할 수 있다.

  • 요청 URL: http://localhost:8080/request-param
  • Content-Type: application/x-www-form-urlencoded
  • 메시지 바디: username=hello&age=20

application/x-www-form-urlencoded 형식은 앞서 다룬 GET 요청의 쿼리 파라미터 형식과 동일하다. 따라서 서버에서는 쿼리 파라미터 조회 메서드를 그대로 사용하여 데이터를 조회할 수 있다.

 

GET과 POST 요청의 차이

  • 클라이언트 입장에서 GET 방식과 POST 방식의 차이점은 GET은 URL에 데이터를 담고, POST는 메시지 바디에 데이터를 담는다는 것이다.
  • 서버 입장에서는 두 방식의 데이터 형식이 동일하므로, request.getParameter() 메서드를 사용하여 편리하게 조회할 수 있다.

정리

  • request.getParameter() 메서드는 GET 방식의 URL 쿼리 파라미터 형식과 POST 방식의 HTML Form 형식을 모두 지원한다. 두 형식 모두 동일하게 데이터를 조회할 수 있다.

참고: Content-Type의 역할

  • GET URL 쿼리 파라미터 방식으로 데이터를 전송할 때는 메시지 바디를 사용하지 않기 때문에 Content-Type이 필요 없다.
  • POST HTML Form 방식으로 데이터를 전송할 때는 HTTP 메시지 바디에 데이터를 포함하여 보내기 때문에, 바디에 포함된 데이터의 형식을 지정하기 위해 Content-Type이 필수적으로 설정된다. 이때 application/x-www-form-urlencoded가 폼 데이터 전송에 사용된다.

Postman 사용한 테스트

HTML Form을 직접 만들기 귀찮을 때는 Postman을 사용하여 테스트할 수 있다.

  1. POST 요청을 선택한다.
  2. Body에서 x-www-form-urlencoded를 선택하고, 데이터를 입력한다.
  3. Headers에서 Content-Type: application/x-www-form-urlencoded로 설정되었는지 확인한다.

이 과정을 통해 서버로 데이터를 POST 방식으로 전송하고, 올바르게 처리되었는지 테스트할 수 있다.

 

HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트

이번에는 HTTP 메시지 바디에 데이터를 직접 담아 API로 전송하는 방법을 알아보자. 주로 HTTP API에서 사용되며, JSON, XML, TEXT 형식의 데이터를 사용한다. 여기서는 가장 단순한 텍스트 메시지를 전송하고 이를 처리하는 방법을 다룬다.

 

데이터 형식

  • API 요청 시 주로 사용하는 데이터 형식
    • JSON
    • XML
    • TEXT
  • HTTP 메서드: POST, PUT, PATCH

HTTP 메시지 바디에 단순 텍스트 전송 예시

HTTP 메시지 바디의 데이터를 InputStream을 사용하여 직접 읽을 수 있다. 이 예제에서는 간단한 텍스트 메시지를 HTTP 메시지 바디에 담아 전송하고 이를 처리하는 서블릿을 구현한다.

 

RequestBodyStringServlet

package hello.servlet.basic.request;

import org.springframework.util.StreamUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body-string")
public class RequestBodyStringServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        // HTTP 메시지 바디의 데이터를 읽기
        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

        System.out.println("messageBody = " + messageBody);

        // 응답 작성
        response.getWriter().write("ok");
    }
}
  • ServletInputStream: 요청 메시지 바디에서 데이터를 읽을 수 있는 입력 스트림을 제공한다.
  • StreamUtils.copyToString: 스트림에서 데이터를 읽어서 지정된 문자표(Charset)를 사용해 문자열로 변환한다. 여기서는 UTF-8을 사용했다.
  • messageBody: 클라이언트가 전송한 데이터를 저장하는 문자열.
  • response.getWriter().write("ok"): 서버에서 클라이언트에게 응답 메시지를 전송한다.

Postman을 사용한 테스트

Postman을 사용해 이 서블릿을 테스트할 수 있다.

  1. POST 요청: http://localhost:8080/request-body-string
  2. Headers
    • Content-Type: text/plain
  3. Body
    • raw 선택
    • 메시지 내용: hello

요청 예시

결과

이 테스트를 통해 서버가 message body에 담긴 텍스트 데이터를 올바르게 처리하고 응답하는지 확인할 수 있다.

 

참고 사항

  • InputStream바이트 코드를 반환하기 때문에, 이를 우리가 읽을 수 있는 문자열로 변환하려면 적절한 문자표(Charset)를 지정해야 한다. 이 예제에서는 UTF-8을 사용했다.
  • POST 요청을 통해 전송되는 데이터는 HTTP 메시지 바디에 담기며, 서버는 이 데이터를 요청에서 읽어 처리할 수 있다.

HTTP 요청 데이터 - API 메시지 바디 - JSON

이번에는 HTTP API에서 주로 사용하는 JSON 형식으로 데이터를 전달하는 방법을 알아보자. JSON은 HTTP API에서 가장 일반적으로 사용되는 데이터 형식이다.

 

JSON 형식 전송

요청 예시

  • URL: POST http://localhost:8080/request-body-json
  • Content-Type: application/json
  • Message Body: {"username": "hello", "age": 20}

결과

messageBody = {"username": "hello", "age": 20}

 

JSON 형식 파싱 추가

JSON 형식으로 전달된 데이터를 파싱 하여 사용할 수 있도록 HelloData라는 객체를 생성한다.

 

HelloData 클래스

package hello.servlet.basic;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HelloData {
    private String username;
    private int age;
}
  • Lombok의 @Getter와 @Setter 어노테이션을 사용하면, 자동으로 getter와 setter 메서드가 생성된다.

Lombok이 생성하는 코드

Lombok이 자동으로 생성하는 코드는 아래와 같다.

public class HelloData {
    private String username;
    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

RequestBodyJsonServlet

이제 JSON 데이터를 처리할 수 있는 서블릿을 만들어보자. Jackson 라이브러리를 사용하여 JSON 데이터를 HelloData 객체로 변환할 수 있다.

package hello.servlet.basic.request;

import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;
import org.springframework.util.StreamUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@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);

        // JSON 데이터를 HelloData 객체로 변환
        HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);

        System.out.println("helloData.username = " + helloData.getUsername());
        System.out.println("helloData.age = " + helloData.getAge());

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

 

Postman을 사용한 테스트

1. POST 요청: http://localhost:8080/request-body-json

2. Content-Type: application/json

3. Body

  • raw 선택
  • JSON 형식 선택
  • 입력 데이터: {"username": "hello", "age": 20}

 

출력 결과

 

참고 사항

  • Jackson 라이브러리(ObjectMapper)를 사용하면 JSON 데이터를 자바 객체로 쉽게 변환할 수 있다.
  • Spring MVC를 사용하면 기본적으로 Jackson 라이브러리가 포함되어 있어 별도의 추가 설정 없이 사용할 수 있다.

추가 참고: HTML form 데이터를 메시지 바디에 담아서 전송하는 경우에도 데이터를 직접 읽을 수 있지만, 일반적으로는 request.getParameter() 메서드를 사용하는 것이 더 편리하다.

'Spring MVC' 카테고리의 다른 글

[MVC] 서블릿(4)  (0) 2024.10.15
[MVC] 서블릿(2)  (1) 2024.10.11
[MVC] 서블릿(1)  (3) 2024.10.10
[MVC] 웹 애플리케이션 이해  (0) 2024.10.10