[MVC][2-2] 서블릿

kiteB·2021년 9월 9일
0

Spring 강의노트

목록 보기
23/24
post-thumbnail

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

HTTP 요청 데이터 전달 방식 중 GET 쿼리 파라미터 방식에 대해 알아보자!

다음 데이터를 클라이언트에서 서버로 전송해보자.

  • username = hello
  • age = 20

메시지 바디 없이, URL의 쿼리 파라미터를 이용해서 데이터를 전달해볼 것이다.
쿼리 파라미터는 URL 뒤에 ?를 붙여서 보낼 수 있다. 추가 파라미터는 &를 이용하면 된다.

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

1. 쿼리 파라미터 조회 메서드

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

2. RequestParamServlet

package hello.servlet.basic.request;

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

/**
 * 1. 파라미터 전송 기능
 * http://localhost:8080/request-param?username=hello&age=20
 * 2. 동일한 파라미터 전송 가능
 * http://localhost:8080/request-param?username=hello&username=kim&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("username = " + username);
        System.out.println("age = " + age);
        
        System.out.println("[단일 파라미터 조회] - end");
        System.out.println();

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

실행 결과

서블릿을 만들고 http://localhost:8080/request-param?username=hello&age=20 파라미터를 전송하면 다음과 같이 출력된다!

[전체 파라미터 조회] - start
username=hello
age=20
[전체 파라미터 조회] - end

[단일 파라미터 조회] - start
username = hello
age = 20
[단일 파라미터 조회] - end

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

위에서는 username=hello 처럼 단일 파라미터를 살펴보았다.

이번에는 username=hello&username=bae처럼 파라미터 이름은 하나인데, 값이 중복인 경우를 살펴보자!

⭐ 주의!

  • request.getParameter() 는 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다! → 지금처럼 중복일 때는 request.getParameterValues()를 사용해야 한다!
  • 이렇게 중복일 때 request.getParameter()를 사용하면 request.getParameterValues()첫 번째 값을 반환한다.

아래의 코드를 추가해주자.

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

http://localhost:8080/request-param?username=hello&username=bae&age=20 파라미터를 전송해보면 다음과 같이 조회된다.

[전체 파라미터 조회] - start
username=hello
age=20
[전체 파라미터 조회] - end

[단일 파라미터 조회] - start
username = hello
age = 20
[단일 파라미터 조회] - end

[이름이 같은 복수 파라미터 조회]
request.getParameterValues(username)
username=hello
username=bae

🔗 전체 코드 확인하기


[ HTTP 요청 데이터 - POST HTML Form ]

이번에는 HTML의 Form을 사용해서 서버로 데이터를 전송해보자.

특징

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

1. hello-form.html 생성

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</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에 접속하면 다음과 같은 화면이 뜬다.

usernameage를 입력한 뒤 전송 버튼을 클릭하면 GET 쿼리 파라미터 때와 동일하게 출력된다!


2. POST 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 형식도 둘 다 지원한다.


3. Postman을 이용한 테스트

위에서 테스트를 하기 위해서 따로 HTML 페이지를 만들었는데 그러면 메번 이렇게 HTML 페이지를 만들어줘야 할까?

그러면 너무너무 귀찮을 것이다..

이렇게 HTML 페이지를 매번 만들지 않고 Postman을 이용하여 간단하게 테스트를 할 수 있다!

위와 같이 설정하고 send를 클릭하면 잘 작동한다!


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

HTTP message body에 데이터를 직접 담아서 요청해보자.

이 방식은 HTTP API에서 주로 사용하는 방식으로,
JSON, XML, TEXT에 사용되는 방식인데 주로 JSON을 사용한다.

먼저 단순한 텍스트 메시지HTTP 메시지 바디에 담아서 전송하고 읽어보자.


1. 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 {

        ServletInputStream inputStream = request.getInputStream();
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        System.out.println("messageBody = " + messageBody);

        response.getWriter().write("ok");
    }
}
  • HTTP message body는 InputStream을 사용해서 직접 읽을 수 있다.

실행 결과

postman을 이용해서 테스트해보면 잘 나온다!

🔗 전체 코드 확인하기


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

이번에는 많이 쓰이는 JSON 형식으로 요청해보자!

JSON 형식을 사용하려면 해당 데이터를 파싱해서 객체화해 줄 객체를 만들어줘야 한다!


1. HelloData

package hello.servlet.basic;

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class HelloData {

    private String username;
    private int age;
}

usernameage를 담을 수 있는 JSON 객체가 만들어졌다!


2. RequestBodyJsonServlet

JSON 방식의 API와 매핑해줄 서블릿 RequestBodyJsonServlet을 만들어주자.

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

        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을 이용해서 테스트해보자!

JSON 형식에 맞춰서 message body를 작성해주면 된다.

🔗 전체 코드 확인하기


[ HTTPServletResponse - 기본 사용법 ]

지금부터는 응답 메시지에 대해 알아보자!

HttpServletResponse 역할

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

HttpServletResponse

package hello.servlet.basic.response;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@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, mustrevalidate");
        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");
    }

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

    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");
    }

}
  • HttpServletResponse.SC_OK
    : 서블릿에서는 HttpServletResponse에서 상태 코드를 코드 자체(Ex. 200/404 등)보다는 의미 있는 상수로 작성해서 오타를 방지하고 가독성을 높일 수 있도록 했다.

🔗 전체 코드 확인


[ HTTP 응답 데이터 - 단순 텍스트, HTML ]

HTTP 응답 메시지는 주로 다음 내용을 담아서 전달한다.

  • 단순 텍스트 응답 (Ex. writer.println("ok");)
  • HTML 응답
  • HTTP API - MessageBody JSON 응답

ResponseHtmlServlet

package hello.servlet.basic.response;

import javax.servlet.ServletException;
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.io.PrintWriter;

@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {

    @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>안녕?</div>");
        writer.println("</body>");
        writer.println("</html>");
    }
}
  • HTTP 응답으로 HTML을 반환할 때content-typetext/html로 지정해야 한다.

실행 결과

http://localhost:8080/response-html로 접속하면 잘 출력되고, 페이지 소스보기를 사용하면 다음과 같이 나타난다.

🔗 전체 코드 확인하기


[ HTML 응답 데이터 - API JSON ]

이번에는 응답 메시지의 API JSON 타입에 대해 알아보자!

ResponseJsonServlet

package hello.servlet.basic.response;

import com.fasterxml.jackson.databind.ObjectMapper;
import hello.servlet.basic.HelloData;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * 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.setHeader("content-type", "application/json");
        response.setCharacterEncoding("utf-8");

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

        //{"username":"kim","age":20}
        String result = objectMapper.writeValueAsString(data);

        response.getWriter().write(result);
    }
} 
  • ObjectMapper를 사용해서 HelloData 객체를 json으로 만들어주고있다.
  • content-typeapplication/json으로 지정해야 한다.
  • objectMapper.writeValueAsString() 메서드를 사용하면 객체를 JSON 문자로 변경할 수 있다.

실행 결과

http://localhost:8080/response-json으로 접속하면 JSON 포맷으로 데이터가 잘 출력되는 것을 확인할 수 있다!

🔗 전체 코드 확인하기

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글