이제부터 본격적으로 순수 Java 코드에서 탈출해보자. 바로 Spring Boot로 넘어가지는 않고, HTTP의 요청 및 응답 과정을 이해하기 위해 먼저 Servlet 부터 차근차근 익혀나가보자.

Servlet?

본래 Servlet은 TOMCAT 같은 WAS(Web Application Server) 를 직접 설치하고 그 위에 코드를 빌드해서 올린 다음, TOMCAT 서버를 실행해야한다.
하지만 우리가 익힐 Spring Boot는 TOMCAT 서버를 내장하고 있어, 그 과정을 생략한다!

image

위와 같이, 내가 보낸 요청과 응답을 기반으로 Servlet Container에서
알아서 요청, 응답 객체를 만들어 나에게 반환해주므로 매우 편리하다.

Servlet 구성

  • @ServeltComponentScan Annotation 하나로 Servlet 등록이 가능하다.
  • @WebServlet(name, urlPatterns) Annotation을 통해 Servlet URL을 등록한다.
    • Servlet Class는 반드시 HttpServlet Class를 상속해야만 한다.
    • 상속한 HttpServlet Class의 protected void service 함수가 핵심!
  • service(HttpServlet request, HttpServletResponse response)
    • Servlet에서 로직을 구현하는 핵심 함수이다.
    • request를 통해 요청을 만들 수 있으며, response를 통해 응답을 만들 수 있다.
  • setAttribute(name, value), getAttribute(name)
    • 추후에 MVC Pattern을 적용할 때에 Model 생성에 편리함을 주는 자체 저장소이다.
Bonus : HTTP Log

application.properties
위 파일에 logging.level.org.apache.coyote.http11=debug를 추가하면,
내가 보낸 요청에 대한 정보들을 로그에 모두 띄울 수 있다.

Servlet Request

Request Header에 대한 조회

  • getMethod(), getProtocol(), getScheme()
  • getRequestURL()… 등의 Method 들을 통해 요청 Header을 직접 조회할 수 있다.
    • 위의 Method들 외에도 매우 많은 Method들이 존재한다.

Request Data에 대한 조회

  • Query Parameter
    • URL에 직접 Parameter을 입력해서 요청을 넣은 경우이다.
      • ex) /url?username=geko&age=30
String username = request.getParameter("username") // 단일 파라미터
request.getParameterNames().asIterator()
       .forEachRemaining(paramName -> System.out.println(paramName +
       "=" + request.getParameter(paramName)));
// 파라미터 이름 모두 조회

String[] usernames = request.getParameterValues("username")
for(String name : usernames){
    System.out.println("username = " + name);
}
// 같은 파라미터 이름, 다른 값 모두 조회
  • HTML Form
    • HTML의 Form Tag를 통해 Data 요청을 입력 받은 경우이다.
    • 반드시 Content-Type은 application/x-www-form-urlencoded로 한다.
    • Parameter의 조회는 위의 Query Parameter와 동일하게 조회가 가능하다.
  • Message body
    • HTML의 Body에 Data를 직접 담아서 요청을 보내는 경우이다.
    • 주로 HTTP API에서 JSON, XML 등의 형태로 보낼 때 사용한다.
    • Data 형식은 주로 JSON을 사용한다.
      • Content-Type: application/json
      • POST, PUT, PATCH Method 사용.
    • 단순 텍스트를 요청에 보내는 경우
ServletInputStream inputStream = request.getInputStream();
// 단순 텍스트는 InputStream으로 받아온다.
String messagebody = StreamUtils.copyToString(inputStream, StandardCharsets._UTF_8);
// InputStream을 String화 시킨다.

response.getWriter().write(messagebody);
// 응답을 통해 페이지에 출력하도록 한다.
  • JSON Data를 보내는 경우
    • 이 때는, JSON Data를 파싱할 객체를 만들어 두어야 한다.
private ObjectMapper objectMapper = new ObjectMapper();

ServletInputStream inputStream = request.getInputStream();
// JSON도 우선은 단순 텍스트이다.
String messagebody = StreamUtils.copyToString(inputStream, StandardCharsets._UTF_8);

HelloData helloData = objectMapper.readValue(messagebody, Hellodata.class);
// ObjectMapper에 단순 텍스트 내에서 값을 파싱해온다.
response.getWriter().write(helloData.getUsername() + " " + helloData.getAge());
// 요청에 보냈던 JSON 값을 파싱해서 helloData의 Getter을 통해 조회가 가능하다.

Servlet Response

Response Header에 대한 설정

  • setStatus(Status Code)
    • 응답 상태코드를 직접 정할 수 있다.
    • ex) HttpServletResponse.SC_OK
  • ```setHeader(“Content-Type”, “text/plain;charset=utf-8”);
  • ```setHeader(“Cache-Control”, “no-cache, no-store, must-revalidate”);
    • 위와 같이 Header의 정보를 직접 기입할 수 있다.
  • setContentType("application/x-www-form-urlencoded")
  • ```setCharacterEncoding(“utf-8”);
    • Content는 위와 같이 직접 설정하는 Method가 따로 제공되기도 한다.
  • ```setHeader(“Set-Cookie”, “myCookie=good”; Max-Age=600”);
  • Cookie cookie = new Cookie("myCookie", "good");
    • Cookie 설정 또한 위 두 가지 방법으로 가능하다.
    • cookie.setMaxAge(600)으로 수명 설정, addCookie(cookie)로 등록한다.
  • response.sendRedirect("/basic/hello-form.html");
    • Redirect 또한 Method로 제공된다.
    • 자동으로 응답코드는 302로 설정되며, 해당 URL로 Redirect한다.

Response Data 반환시키기

  • getWriter() 을 통한 HTML 반환
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
// 타입, 인코딩 설정은 필수다.

PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
wrtier.println("  <div>Hi!</div>");
writer.println("</body>");
writer.println("</html>");
// 이렇게 writer을 통해서 HTML 코드를 직접 칠 수 있다.
  • ObjectMapper와 getWriter()을 통한 JSON 반환
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8");

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

String result = objectMapper.writerValueAsString(data);
// Jackson Library의 JSON을 문자로 바꾸는 Method.
response.getWriter().write(result);

Servlet의 한계

하지만 이런 Servlet도 한계점은 분명히 존재한다.
Servlet으로 개발을 할 때, View를 위해 HTML을 직접 만드는 작업은 자바 코드에
뒤섞여 매우 지저분하고 복잡해 보이기만 한다.

그래서 우리는 이후에 JSP라는 새로운 HTML 작업에 대해 배울 것이다.