[스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술] 02. 서블릿

Turtle·2024년 6월 26일
0
post-thumbnail

🙄서블릿

✔️내장 톰켓 서버 생성

  1. 스프링 부트가 내장 톰켓 서버를 생성
  2. 내장 톰켓 서버에는 서블릿 컨테이너가 존재
  3. 서블릿 컨테이너에 서블릿을 생성

✔️HTTP 요청, HTTP 응답 메시지

  1. 클라이언트로부터 HTTP 요청이 들어오면 request, response를 생성

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

  1. HTTP 요청 메시지를 기반으로 request를 만들고 서블릿 컨테이너 내부에 있는 서블릿의 service() 메서드를 호출
  2. 작업이 끝나면 response에 작업 결과를 전달하고 이를 기반으로 HTTP 응답 메시지를 생성해 반환

🙄HttpServletRequest

✔️개발자 대신에 HTTP 요청 메시지를 파싱

  1. HTTP 요청 메시지 Header 부분
package hello.servlet.request;

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

import java.io.IOException;

@WebServlet(name = "requestServlet", urlPatterns = "/request-header")
public class RequestServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		printStartLine(req);
		printHeaders(req);
		printHeaderUtils(req);
		printEtc(req);
	}

	// start line 정보
	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 ---");

		request.getHeaderNames().asIterator().forEachRemaining(headerName -> System.out.println(headerName + " : " + 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();
	}
}

🙄HttpServletRequest - 요청 데이터 개요

✔️GET - 쿼리 파라미터 & POST - HTML 폼

  1. 파라미터 조회 가능
package hello.servlet.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;

@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.getParameterNames().asIterator().forEachRemaining(paramName -> System.out.println(paramName + " = " + req.getParameter(paramName)));

		String username = req.getParameter("username");
		int age = Integer.parseInt(req.getParameter("age"));

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

		String[] usernames = req.getParameterValues("username");
		for (String s : usernames) {
			System.out.println(s);
		}
	}
}

✔️HTTP API - JSON

  1. API를 통한 데이터 전송 시 사용 → 일반적으로 JSON을 많이 사용
package hello.servlet.request;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.StreamUtils;

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 req, HttpServletResponse resp) throws ServletException, IOException {
		ServletInputStream inputStream = req.getInputStream();
		String s = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
		System.out.println(s);

		// String 타입의 s를 JSON 객체로 변환
		HelloData helloData = objectMapper.readValue(s, HelloData.class);
		System.out.println(helloData.getUsername());
		System.out.println(helloData.getAge());
	}

	@Getter
	@Setter
	static class HelloData {
		private String username;
		private String age;

		@Override
		public String toString() {
			return "HelloData{" +
					"username='" + username + '\'' +
					", age='" + age + '\'' +
					'}';
		}
	}
}

🙄HttpServletResponse

✔️HTTP 응답 메시지 생성

  1. HTTP 응답 메시지 헤더 부분
package hello.servlet.response;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.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 req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setStatus(HttpServletResponse.SC_OK);
		resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
		resp.setHeader("Pragma", "no-cache");
		resp.setHeader("my-header", "hello");

		content(resp);

		cookie(resp);

		redirect(resp);
	}

	private void content(HttpServletResponse response) {
		response.setContentType("text/plain");
		response.setCharacterEncoding("utf-8");
	}

	private void cookie(HttpServletResponse response) {
		Cookie cookie = new Cookie("myCookie", "good");
		cookie.setMaxAge(600); // 600초
		response.addCookie(cookie);
	}

	private void redirect(HttpServletResponse response) throws IOException {
		response.setStatus(HttpServletResponse.SC_FOUND);
		response.sendRedirect("/basic/hello-form.html");
	}
}

🙄HttpServletResponse - 응답 데이터 개요

✔️HTML 응답

  1. HTML 형식으로 응답을 보내고 싶다면 contentType을 text/html로 설정해야한다.
package hello.servlet.response;

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.io.PrintWriter;

@WebServlet(name = "responseHtmlServlet", urlPatterns = "/response-html")
public class ResponseHtmlServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html");
		resp.setCharacterEncoding("UTF-8");

		PrintWriter writer = resp.getWriter();

		writer.write("<html>");
		writer.write("<body>");
		writer.write("<div>반갑습니다.</div>");
		writer.write("</body>");
		writer.write("</html>");
	}
}

✔️HTTP API - Message Body JSON 응답

  1. Json 형식으로 응답을 보내고 싶다면 contentType을 application/json으로 설정해야한다.
package hello.servlet.response;

import com.fasterxml.jackson.databind.ObjectMapper;
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 lombok.Getter;
import lombok.Setter;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "responseJsonServlet", urlPatterns = "/response-json")
public class ResponseJsonServlet extends HttpServlet {

	private ObjectMapper objectMapper = new ObjectMapper();

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("application/json");
		resp.setCharacterEncoding("UTF-8");

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

		String s = objectMapper.writeValueAsString(helloData);
		resp.getWriter().write(s);
	}

	@Getter
	@Setter
	static class HelloData {
		private String username;
		private int age;
	}
}

❓ObjectMapper

JSON 객체를 POJO(Plain Old Java Object) 형태로 역직렬화하거나 POJO 형태를 JSON 객체로 직렬화할 때 이 ObjectMapper를 사용한다.

Class ObjectMapper 참고 문서

0개의 댓글