서블릿

born_a·2022년 7월 17일
0

프로젝트 생성


Jar: 스프링 부트가 빌드된 결과에 톰캣 서버를 내장해서 바로 할때 씀
War: 톰캣을 따로 설치 하기도 하고 톰캣 내장 하기도 한다.
그러나 JSP 돌리려면 War 선택해야함


Spring Web : WAS 서버가 내장됨(톰캣 서버)


롬복 설치 후 설정

스프링 부트 환경에서 서블릿 등록하고 사용해보자.

참고
서블릿은 톰캣 같은 웹 애플리케이션 서버를 직접 설치하고,그 위에 서블릿 코드를 클래스 파일로 빌드해서
올린 다음, 톰캣 서버를 실행하면 된다. 하지만 이 과정은 매우 번거롭다.
스프링 부트는 톰캣 서버를 내장하고 있으므로, 톰캣 서버 설치 없이 편리하게 서블릿 코드를 실행할 수
있다.

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

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

@ServletComponentScan // 서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
	public static void main(String[] args) {
		SpringApplication.run(ServletApplication.class, args);
	}
}

스프링이 자동으로 내 패키지를 포함해서 하위 패키지를 다 뒤져서
서블릿을 찾아 서블릿을 등록해서 실행할 수 있게 도와준다.

@WebServlet : 서블릿 애노테이션
name: 서블릿 이름
urlPatterns: URL 매핑
name과 urlPatterns는 이름 겹치면 안됨

/hello 로 오면 이게 실행됨.
서블릿은 HttpServlet을 상속받아야함

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
protected class HelloServlet extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        super.service(req, res);
    }
}

서블릿이 호출되면 서비스 메소드가 호출됨.
HTTP 요청을 통해 매핑된 URL이 호출되면 서블릿 컨테이너는 다음 메서드를 실행한다.

ctrl+O 한뒤 서비스 메소드 추가

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("HelloServlet.service");
    }
}


실행 시 빈화면이 뜨게 된다.
아무것도 응답한게 없으므로 빈화면이 뜨게됨

HTTP 요청이 오면 WAS가(서블릿 컨테이너가) request, response 객체를 만들어서 서블릿에 던져줌

WAS 서버들이 표준 서블릿을 구현 - 구현체들이 있겠지?
구현체들이 찍히게 됨

org.apache.catalina. : 톰캣쪽 라이브러리

ctrl+R : 서버 재시작(마지막 실행한걸 다시 시작)

http://localhost:8080/hello?username=kim url 입력 후

request.getParameter("username"); 로 파라미터를 알 수 있다.

response에 값을 넣으면 웹 브라우저에 응답하는 Http 응답 메시지에 데이터가 담겨서 나가게 됨

@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/plain");
        response.setCharacterEncoding("utf-8"); // 얘네는 헤더 정보에 들어가는 것.
        response.getWriter().write("hello " + username); //http메시지 바디에 데이터가 들어감
    }
}


보낸 데이터 그대로 있다.


개발자 도구에서 확인가능

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

application.properties에
logging.level.org.apache.coyote.http11=debug 추가하면

서버를 다시 시작하고, 요청해보면 서버가 받은 HTTP 요청 메시지를 출력하는 것을 확인할 수 있다

참고
운영서버에 이렇게 모든 요청 정보를 다 남기면 성능저하가 발생할 수 있다. 개발 단계에서만 적용하자.

서블릿 컨테이너 동작 방식 설명

내장 톰캣 서버 생성

스프링부트 실행되면서 스프링부트가 내장 톰캣 서버를 띄워준다
톰캣 서버는 내부에 서블릿 컨테이너 기능을 가지고 있음
서블릿 컨테이너를 통해 서블릿을 생성해준다

HTTP 요청, HTTP 응답 메시지

/hello?username=world 라고 치면
웹 브라우저가 요렇게 HTTP 메시지를 만들어서 서버에 던짐

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

HTTP 요청이 오면 서버는 request, response 객체를 만들어서
helloServlet을 호출, 거기에 서비스 메소드를 호출하면서
response를 넘겨줌
WAS 서버가 response 정보 가지고 HTTP 응답 메시지를 만들어서 반환해주면
웹 브라우저에서 hello world를 볼 수 있게 됨.

참고

HTTP 응답에서 Content-Length는 웹 애플리케이션 서버가 자동으로 생성해준다.

welcome 페이지 추가

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

welcomepage : 내 도메인 왔을 때 첫 화면

HttpServletRequest - 개요

HttpServletRequest 역할

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

조회 기능

HttpServletRequest를 사용하면 다음과 같은 HTTP 요청 메시지를 편리하게 조회할 수 있다.

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

임시 저장소 기능

해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능
저장: request.setAttribute(name, value)
조회: request.getAttribute(name)

세션 관리 기능

request.getSession(create: true)

중요
HttpServletRequest, HttpServletResponse를 사용할 때 가장 중요한 점은 이 객체들이 HTTP 요청
메시지, HTTP 응답 메시지를 편리하게 사용하도록 도와주는 객체라는 점이다. 따라서 이 기능에 대해서
깊이있는 이해를 하려면 HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해해야 한다.

HttpServletRequest - 기본 사용법

ctrl+alt+shift+T : Extract Method

start-line 정보

@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        printStartLine(request);
    }

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


Header 모든 정보

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

request.getHeaderNames() : HTTP 요청 메시지에 있는 모든 헤더 정보를 다 꺼낼 수 있다

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

request.getLocale() : 가장 높은걸 자동으로 뽑힘


request.getContentType() = null 인 이유는 GET 방식이라 바디에 아무것도 안 담겨 있기 때문

postman으로 send 시에

request.getHeader("host"); 이런식으로 원하는 값 꺼낼 수 있다.

기타 정보

기타 정보는 HTTP 메시지의 정보는 아니다.

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


remote 정보 : 요청이 온거에 대한 정보
local 정보 : 나의 서버에 대한 정보

내부 네트워크 커넥션에 대한 정보이다

지금까지 HttpServletRequest를 통해서 HTTP 메시지의 start-line, header 정보 조회 방법을 이해했다.
이제 본격적으로 HTTP 요청 데이터를 어떻게 조회하는지 알아보자.

HTTP 요청 데이터

개요

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

이런 식으로 폼데이터를 바디로 전송할때는 POST 방식만 허용됨

POST- HTML Form 예시

content-type : 어떤 타입의 데이터인지 말해줌

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

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

전달 데이터
username=hello
age=20

메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하자.
예) 검색, 필터, 페이징등에서 많이 사용하는 방식

쿼리 파라미터는 URL에 다음과 같이 ? 를 시작으로 보낼 수 있다. 추가 파라미터는 & 로 구분하면 된다.

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

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

쿼리 파라미터 조회 메서드

request.getParameterNames();//모든 요청 파라미터를 다 꺼낼 수 있음

/**

    1. 파라미터 전송 기능
  • 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("[단일 파라미터 조회]");
String username = request.getParameter("username");
System.out.println("username = " + username);
String age = request.getParameter("age");
System.out.println("age = " + age);

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

username=hello&username=kim 과 같이 파라미터 이름은 하나인데, 값이 중복이면 어떻게 될까?
request.getParameter() 는 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다.
지금처럼 중복일 때는 request.getParameterValues() 를 사용해야 한다.
참고로 이렇게 중복일 때 request.getParameter() 를 사용하면 request.getParameterValues() 의
첫 번째 값을 반환한다.

System.out.println("[이름이 같은 복수 파라미터 조회]");
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


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

참고
content-type은 HTTP 메시지 바디의 데이터 형식을 지정한다.
GET URL 쿼리 파라미터 형식으로 클라이언트에서 서버로 데이터를 전달할 때는 HTTP 메시지 바디를
사용하지 않기 때문에 content-type이 없다.
POST HTML Form 형식으로 데이터를 전달하면 HTTP 메시지 바디에 해당 데이터를 포함해서 보내기
때문에 바디에 포함된 데이터가 어떤 형식인지 content-type을 꼭 지정해야 한다. 이렇게 폼으로 데이터를
전송하는 형식을 application/x-www-form-urlencoded 라 한다.

Postman을 사용한 테스트

이런 간단한 테스트에 HTML form을 만들기는 귀찮다. 이때는 Postman을 사용하면 된다.

Postman 테스트 주의사항
POST 전송시
-Body x-www-form-urlencoded 선택
-Headers에서 content-type: application/x-www-form-urlencoded 로 지정된 부분 꼭 확인

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

HTTP message body에 데이터를 직접 담아서 요청

  • HTTP API에서 주로 사용, JSON, XML, TEXT
  • 데이터 형식은 주로 JSON 사용
  • POST, PUT, PATCH

먼저 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하고, 읽어보자.
HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.

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

PostMan으로 request 전송

문자 전송
POST http://localhost:8080/request-body-string
content-type: text/plain
message body: hello
결과: messageBody = hello

메시지바디에 넣었던 데이터가 그대로 나옴

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

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

이번에는 HTTP API에서 주로 사용하는 JSON 형식으로 데이터를 전달해보자.

JSON 형식 전송

POST http://localhost:8080/request-body-json
content-type: application/json
message body: {"username": "hello", "age": 20}
결과: messageBody = {"username": "hello", "age": 20}

JSON 형식 파싱 추가

JSON 형식으로 파싱할 수 있게 객체를 하나 생성하자

getter setter : Alt + insert
lombok이 제공하는 @Getter , @Setter 덕분에 다음 코드가 자동으로 추가된다.

package hello.servlet.basic;

import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class HelloData {
    private String username;
    private int age;
    
    //==== lombok 생성 코드 ====//
 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;
 }


}
@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet 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);
    }
}

이전에 만든 HelloData로 변환시켜보자 - json 라이브러리 필요

@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json")
public class RequestBodyJsonServlet extends HttpServlet {
    //jackson : json 라이브러리
    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으로 실행해보자.

POST http://localhost:8080/request-body-json
content-type: application/json (Body raw, 가장 오른쪽에서 JSON 선택)
message body: {"username": "hello", "age": 20}

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

참고
HTML form 데이터도 메시지 바디를 통해 전송되므로 직접 읽을 수 있다.
하지만 편리한 파리미터 조회기능( request.getParameter(...) )을 이미 제공하기 때문에 파라미터 조회 기능을 사용하면 된다.

HttpServletResponse - 기본 사용법

HttpServletResponse 역할

HTTP 응답 메시지 생성

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

편의 기능 제공

Content-Type, 쿠키, Redirect

hello.servlet.basic.response.ResponseHeaderServlet

@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //응답 코드 세팅
        //[ststus-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-reb-validate");
        response.setHeader("Pragma","no-cache");
        response.setHeader("my-header","hello");

        //[Header 편의 메서드]
        //content(response);
        //cookie(response);
        redirect(response);
        
        //[message body]
        PrintWriter writer = response.getWriter();
        writer.write("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");
    }


302면서 location이 있기때문에 리다이렉션 작용이 일어난것

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

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

  • 단순 텍스트 응답
    앞에서 살펴봄 ( writer.println("ok"); )
  • HTML 응답
  • HTTP API - MessageBody JSON 응답

HTML 응답

response.setContentType("text/html"); //content-type이 있어야 웹브라우저가 html 이구나 하고 정상적으로 렌더링함

hello.servlet.web.response.ResponseHtmlServlet

@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"); //content-type이 있어야 웹브라우저가 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 응답 데이터 - API JSON

hello.servlet.web.response. ResponseJsonServlet

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

        //Http 응답 데이터를 제이슨으로 뿌려보자
        //{"username":"kim","age":20}
        String result = objectMapper.writeValueAsString(helloData);
        response.getWriter().write(result);
    }
}

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

참고
application/json 은 스펙상 utf-8 형식을 사용하도록 정의되어 있다. 그래서 스펙에서 charset=utf-8과 같은 추가 파라미터를 지원하지 않는다. 따라서 application/json 이라고만 사용해야지 application/json;charset=utf-8 이라고 전달하는 것은 의미 없는 파라미터를 추가한 것이 된다.
response.getWriter()를 사용하면 추가 파라미터를 자동으로 추가해버린다. 이때는 response.getOutputStream()으로 출력하면 그런 문제가 없다.

0개의 댓글