개발/스프링 MVC

(스프링 MVC 1편) 2. 서블릿

용꿀 2023. 3. 10. 13:24

이 글은 김영한 님의 스프링 MVC 1편 수강 후 정리한 글입니다.

(https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard)

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., -

www.inflearn.com


프로젝트 생성

1. Spring initializr로 스프링 프로젝트 생성

스프링 부트 스타터 사이트(https://start.spring.io)로 이동해서 다음과 같이 스프링 프로젝트를 생성한다.

※ Packaging는 Jar가 아니라 JSP를 실행하기 위해서 War를 선택해야 한다. 

 

프로젝트에서 기본 메인 클래스(ServletApplication.main()) 실행 후 http://localhost:8080에 접속했을 때, Whitelabel Error Page가 나오면 정상 동작하는 것이다.

 

2. IntelliJ Gradle 대신에 자바 직접 실행 설정

File -> Setting -> Build, Execution, Deployment -> Build Tools -> Gradle 순으로 설정에 접속하여
Build and run using: Gradle IntelliJ IDEA
Run tests using: Gradle IntelliJ IDEA

위와 같이 변경한다.

 

3. 롬복 적용

1. File -> Setting -> plugin -> lombok 검색 실행 (재시작)
2. File -> Setting -> Annotation Processors 검색 -> Enable annotation processing 체크 (재시작)
3. 임의의 테스트 클래스를 만들고 @Getter, @Setter 확인

위와 같은 과정을 거쳐 롬복을 프로젝트에 적용한다.

 

4. Postman 설치

Postman 사이트(https://www.postman.com/downloads)에서 Postman을 다운로드하고 설치한다.

Hello 서블릿

1. 스프링 부트 서블릿 환경 구성

스프링 부트는 직접 서블릿을 등록하여 사용할 수 있도록 @ServletComponentScan을 지원한다.

사용법은 아래와 같이 프로젝트 기본 메인 클래스에 @ServletComponentScan을 추가하면 된다.

그러면 하위 패키지를 모두 스캔하여 자동으로 서블릿을 실행할 수 있도록 등록해 준다.

// ServletApplication.java
@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {

   public static void main(String[] args) {
      SpringApplication.run(ServletApplication.class, args);
   }

}

 

2. 서블릿 등록하기

다음으로 실제 동작하는 서블릿 코드를 등록해 보자.

hello.servlet.basic.HelloServlet을 다음과 같이 생성한다.

// HelloServlet.java
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("HelloServlet.service");
        System.out.println("request = " + request);
        System.out.println("response = " + response);

        String username = request.getParameter("username");
        System.out.println("username = " + username);

        response.setContentType("text/plan");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write("hello " + username);
    }
}

위의 코드는 HTTP 요청을 통해  username이라는 이름의 Parameter로 들어온 값을 username 변수에 저장하고, 이를 출력하는 코드이다.

@WebServlet 서블릿 애노테이션 : name - 서비스 이름, urlPatterns - URL 매핑

HTTP 요청을 통해 매핑된 URL(http://localhost:8080/hello?username=example)이 호출되면 서블릿 컨테이너는 위의 service 메서드를 실행한다. 그리고 다음과 같이 콘솔에 출력된다.

HelloServlet.service
request = org.apache.catalina.connector.RequestFacade@xxxxxxxx
response = org.apache.catalina.connector.ResponseFacade@xxxxxxxx
username = example

3. HTTP 요청 메시지 로그로 확인하기

application.properties에 다음 설정을 추가한다.

서버 재시작 후에 새롭게 요청해 보면 아래와 같이 서버가 받은 HTTP 요청 메시지를 콘솔에서 출력하는 것을 확인할 수 있다.

[GET /hello?username=example HTTP/1.1
Host: localhost:8080
Connection: keep-alive
...
]

4. Welcome 페이지 추가

webapp 경로에 index.html을 두면 http://localhost:8080 호출 시 index.html 페이지가 열린다.

<!--index.html-->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li><a href="basic.html">서블릿 basic</a></li>
</ul>
</body>
</html>

welcome Page(index.html)

welcome 페이지를 완성하였으면, 이번 장에서 사용할 basic.html 파일을 같은 위치에 생성한다.

<!--basic.html-->
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li>hello 서블릿
        <ul>
            <li><a href="/hello?username=servlet">hello 서블릿 호출</a></li>
        </ul>
    </li>
    <li>HttpServletRequest
        <ul>
            <li><a href="/request-header">기본 사용법, Header 조회</a></li>
            <li>HTTP 요청 메시지 바디 조회
                <ul>
                    <li><a href="/request-param?username=hello&age=20">GET -
                        쿼리 파라미터</a></li>
                    <li><a href="/basic/hello-form.html">POST - HTML Form</a></
                    li>
                    <li>HTTP API - MessageBody -> Postman 테스트</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>HttpServletResponse
        <ul>
            <li><a href="/response-header">기본 사용법, Header 조회</a></li>
            <li>HTTP 응답 메시지 바디 조회
                <ul>
                    <li><a href="/response-html">HTML 응답</a></li>
                    <li><a href="/response-json">HTTP API JSON 응답</a></li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
</body>
</html>

basic.html 화면

HttpServletRequest

1. 개요

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

그 외에도 해당 HTTP 요청이 끝날 때까지 유지되는 임시 저장소, 세션 관리 같은 부가적인 기능도 제공한다.

HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해해야 한다.

 

2. 기본 사용법

hello.servlet.basic.request.RequestHeaderServlet을 다음과 같이 생성한다.

// RequestHeaderServlet.class
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {

    // protected로 된 service 메소드를 Ctrl+O를 사용하여 Override
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        printStartLine(request);
        printHeaders(request);
        printHeaderUtils(request);
        printEtc(request);
    }

    // start-line 정보
    private static void printStartLine(HttpServletRequest request) {
        System.out.println("--- REQUEST-LINE - start ---");
        System.out.println("request.getMethod() = " + request.getMethod()); //GET
        System.out.println("request.getProtocol() = " + request.getProtocol()); //HTTP/1.1
        System.out.println("request.getScheme() = " + request.getScheme()); //http
        // http://localhost:8080/request-header
        System.out.println("request.getRequestURL() = " + request.getRequestURL());
        // /request-header
        System.out.println("request.getRequestURI() = " + request.getRequestURI());
        //username=hi
        System.out.println("request.getQueryString() = " + request.getQueryString());
        System.out.println("request.isSecure() = " + request.isSecure()); //https 사용 유무
        System.out.println("--- REQUEST-LINE - end ---");
        System.out.println();
    }

    // 헤더 정보
    private void printHeaders(HttpServletRequest request) {
        System.out.println("--- Headers - start ---");
        /* 과거의 사용법
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
        System.out.println(headerName + ": " + request.getHeader(headerName));
        }
        */
        request.getHeaderNames().asIterator()
                .forEachRemaining(headerName -> System.out.println(headerName + ": "
                        + request.getHeader(headerName)));
                        System.out.println("--- Headers - end ---");
        System.out.println();
    }

    //Header 편리한 조회
    private void printHeaderUtils(HttpServletRequest request) {
        System.out.println("--- Header 편의 조회 start ---");
        System.out.println("[Host 편의 조회]");
        System.out.println("request.getServerName() = " +
                request.getServerName()); //Host 헤더
        System.out.println("request.getServerPort() = " +
                request.getServerPort()); //Host 헤더
        System.out.println();
        System.out.println("[Accept-Language 편의 조회]");
        request.getLocales().asIterator()
                .forEachRemaining(locale -> System.out.println("locale = " +
                        locale));
        System.out.println("request.getLocale() = " + request.getLocale());
        System.out.println();
        System.out.println("[cookie 편의 조회]");
        if (request.getCookies() != null) {
            for (Cookie cookie : request.getCookies()) {
                System.out.println(cookie.getName() + ": " + cookie.getValue());
            }
        }
        System.out.println();
        System.out.println("[Content 편의 조회]");
        System.out.println("request.getContentType() = " +
                request.getContentType());
        System.out.println("request.getContentLength() = " +
                request.getContentLength());
        System.out.println("request.getCharacterEncoding() = " +
                request.getCharacterEncoding());
        System.out.println("--- Header 편의 조회 end ---");
        System.out.println();
    }

    //기타 정보
    private void printEtc(HttpServletRequest request) {
        System.out.println("--- 기타 조회 start ---");
        System.out.println("[Remote 정보]");
        System.out.println("request.getRemoteHost() = " +
                request.getRemoteHost()); //
        System.out.println("request.getRemoteAddr() = " +
                request.getRemoteAddr()); //
        System.out.println("request.getRemotePort() = " +
                request.getRemotePort()); //
        System.out.println();
        System.out.println("[Local 정보]");
        System.out.println("request.getLocalName() = " +
                request.getLocalName()); //
        System.out.println("request.getLocalAddr() = " +
                request.getLocalAddr()); //
        System.out.println("request.getLocalPort() = " +
                request.getLocalPort()); //
        System.out.println("--- 기타 조회 end ---");
        System.out.println();
    }
}

결과는 다음과 같다.

--- REQUEST-LINE - start ---
request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = http://localhost:8080/request-header
request.getRequestURI() = /request-header
request.getQueryString() = null
request.isSecure() = false
--- REQUEST-LINE - end ---

--- Headers - start ---
host: localhost:8080
connection: keep-alive
cache-control: max-age=0
sec-ch-ua: "Chromium";v="110", "Not A(Brand";v="24", "Google Chrome";v="110"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 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.7
sec-fetch-site: none
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
accept-encoding: gzip, deflate, br
accept-language: ko-KR,ko;q=0.9
--- Headers - end ---

--- Header 편의 조회 start ---
[Host 편의 조회]
request.getServerName() = localhost
request.getServerPort() = 8080

[Accept-Language 편의 조회]
locale = ko_KR
locale = ko
request.getLocale() = ko_KR

[cookie 편의 조회]

[Content 편의 조회]
request.getContentType() = null
request.getContentLength() = -1
request.getCharacterEncoding() = UTF-8
--- Header 편의 조회 end ---

--- 기타 조회 start ---
[Remote 정보]
request.getRemoteHost() = 0:0:0:0:0:0:0:1
request.getRemoteAddr() = 0:0:0:0:0:0:0:1
request.getRemotePort() = 50306

[Local 정보]
request.getLocalName() = 0:0:0:0:0:0:0:1
request.getLocalAddr() = 0:0:0:0:0:0:0:1
request.getLocalPort() = 8080
--- 기타 조회 end ---

이렇게 HttpServletRequest를 통해서 HTTP 요청 메시지의 start-line, header 등에 대한 정보 조회를 할 수 있다.

Http 요청 데이터

1. 개요

HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법은 주로 3가지가 있다.

  • GET - 쿼리 파라미터

메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달하는 방법이다.

검색, 필터, 페이징 등에서 많이 사용하는 방식이다.

ex) /url?paramName=value&paramName2=value2

  • POST - HTML Form

메시지 바디에 username=hello&age=20와 같이 쿼리 파라미터 형식으로 전달하는 방법이다. (content-type: application/x-www-form-urlencoded)
예) HTML Form을 사용한 회원 가입, 상품 주문 등

  • HTTP Message Body

HTTP API에서 주로 사용하는 방식이며, JSON, XML, TEXT를 사용하여 데이터를 전달할 수 있다.
ex) POST, PUT, PATCH 방식

 

2. GET 쿼리 파라미터

클라이언트에서 서버로 username=hello, age=20라는 정보를 전송한다고 하자.

메시지 바디 없이 URL의 쿼리 파라미터에 포함하여 전송할 것이다.

쿼리 파라미터는 url 이후에 '?'를 시작으로 보낼 수 있으며 추가 파라미터는 '&'을 사용하여 보내면 된다.

ex) /url?paramName=value&paramName2=value2

 

서버에서는 HttpServletRequest가 제공하는 메서드들을 사용하여 편리하게 조회할 수 있다.

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

이들을 직접 사용해 보자.

hello.servlet.basic.request.RequestParamServlet을 다음과 같이 생성한다.

// RequestParamServlet.class
/**
 1. 파라미터 전송 기능
 http://localhost:8080/request-param?username=hello&age=20

 2. 동일한 파라미터 전송 가능
 * http://localhost:8080/request-param?username=hello&username=kim&cho=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");
        /* 옛날 방식
        Enumeration<String> parameterNames = request.getParameterNames();*/
        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");
        System.out.println("username = " + username);
        String age = request.getParameter("age");
        System.out.println("age = " + age);
        System.out.println("[단일 파라미터 조회] - end");

        System.out.println();

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

        response.getWriter().write("ok"); // 화면에 ok를 표시하기 위함
    }
}

결과는 다음과 같다.

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

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

[이름이 같은 복수 파라미터 조회] - start
name = hello
name = cho
[이름이 같은 복수 파라미터 조회] - end

username=hello&username=cho와 같이 파라미터 이름은 하나인데, 값이 중복이라면 request.getParameter()를 사용해서는 안된다. 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다.
중복일 때는 request.getParameterValues()를 사용해야 한다. 참고로 중복일 때 request.getParameter()를 사용하면 request.getParameterValues()의 첫 번째 값(첫 번째로 나타난 값)을 반환한다.

 

3. HTTP 요청 데이터 - Post Html Form

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

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

<!--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로 접속하면 다음과 같은 Form을 확인할 수 있다.

여기서 전송 버튼을 눌러 POST HTML Form을 전송하면 웹 브라우저는 다음 형식으로 HTTP 메시지를 만든다.

웹 브라우저 개발자 모드(F12)로 확인할 수 있다.
요청 URL: http://localhost:8080/request-param
content-type: application/x-www-form-urlencoded
message body: username=xxxx&age=xx

 

application/x-www-form-urlencoded 형식 또한 앞서 GET - 쿼리 파라미터 형식과 같다.
따라서 앞에서 만든 쿼리 파라미터 조회 메서드를 그대로 사용하면 된다.
클라이언트 입장에서는 두 방식에 차이가 있지만, 서버 입장에서는 둘의 형식이 동일하기에 request.getParameter()로 편리하게 구분 없이 조회할 수 있다.
정리하면 request.getParameter()는 GET URL 쿼리 파라미터 형식도 지원하고, POST HTML Form
형식도 둘 다 지원한다.

※ content-type은 HTTP 메시지 바디의 데이터 형식을 지정하는 것이다.

그렇기에 GET URL 쿼리 파라미터 형식으로 데이터를 전달할 때는 HTTP 메시지 바디를 사용하지 않으므로 content-type이 없고, POST HTML FORM 형식일 때는 HTTP 메시지 바디에 데이터를 포함해서 보내므로 content-type이 지정되어 있다.

 

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

HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.

이를 직접 사용해 보자.

hello.servlet.basic.request.RequestBodyStringServlet을 다음과 같이 생성한다.

// RequestBodyStringServlet
@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 코드를 읽을 수 있게 Charset 지정
        String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

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

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

inputStream은 byte 코드를 반환한다. byte 코드를 우리가 읽을 수 있는 문자(String)로 보려면 문자표(Charset)를 지정해주어야 한다.

 

Postman을 사용해 Text를 Body에 담아 다음과 같이 Post 요청을 보내보자.

콘솔 창에서 다음과 같이 데이터가 잘 전달된 것을 확인할 수 있다.

 

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

이번에는 JSON을 사용하여 데이터를 전달해 보겠다.

먼저 JSON 형식으로 파싱 할 수 있도록 관련 객체를 생성하자.

hello.servlet.basic.HelloData를 생성한다.

//HelloData.class
@Getter // 롬복 : 자동으로 Getter 생성
@Setter // 롬복 : 자동으로 Setter 생성
public class HelloData {
    private String username;
    private int age;
}

다음으로 hello.servlet.basic.request.RequestBodyJsonServlet을 다음과 같이 생성한다.

// RequestBodyJsonServlet.class
@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를 Body에 담아 다음과 같이 Post 요청을 보내보자.

콘솔 창에서 다음과 같이 데이터가 잘 전달된 것을 확인할 수 있다.

※ JSON 결과를 파싱 하여 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson과 같은 JSON 변환
라이브러리를 추가해서 사용해야 한다. 스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson
라이브러리(ObjectMapper)를 함께 제공한다.

 

※ HTML form 데이터도 메시지 바디를 통해 전송되므로 직접 읽을 수 있다.

하지만 더 편리한 파라미터 조회 기능(request.getParameter(...))을 제공하기 때문에 이를 사용하면 된다.

 

Http 응답 데이터

1. HttpServletResponse 역할

HTTP 응답 메시지 생성

  • HTTP 응답코드 지정
  • 헤더 생성
  • 바디 생성

편의 기능 제공

  • Content-Type
  • 쿠키
  • Redirect

2. HttpServletResponse - 기본 사용법

hello.servlet.basic.response.ResponseHeaderServlet을 다음과 같이 생성한다.

// ResponseHeaderServlet.class
@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-header]
        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. HTTP 응답 데이터 - 단순 텍스트, HTML

hello.servlet.web.response.ResponseHtmlServlet을 다음과 같이 생성한다.

// ResponseHtmlServlet.class
@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-type을 text/html로 지정해야 한다.

 

프로그램 실행 후 http://localhost:8080/response-html에 접속하여 보면

다음과 같이 html 파일로 잘 전달된 것을 확인할 수 있다!

 

4. HTTP 응답 데이터 - API JSON

이번엔 API를 응답 메시지에 담아 전달해 보겠다.

hello.servlet.web.response.ResponseHtmlServlet을 다음과 같이 생성한다.

// ResponseJsonServlet.class 
@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: text/html;charset=utf-8
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");

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

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

HTTP 응답으로 JSON을 반환할 때는 content-type을 application/json로 지정해야 한다.
Jackson 라이브러리가 제공하는 objectMapper.writeValueAsString()을 사용하면 객체를 JSON 문자로 변경할 수 있다.

 

프로그램 실행 후 http://localhost:8080/response-json에 접속하여 보면

다음과 같이 JSON이 잘 전달된 것을 확인할 수 있다!