프로그래밍 공방

[Spring] 2. Servlet / 서블릿 본문

개발/스프링

[Spring] 2. Servlet / 서블릿

hyosupsong 2021. 10. 15. 22:37

Servlet / 서블릿

클라이언트의 요청을 받아 웹페이지를 동적으로 생성하여 응답하는 서버측 프로그램

* 서블릿은 아래 작업들을 대신해서 처리해준다
- 서버 TCP/IP 연결 대기, 소켓 연결
- 웹 브라우저가 생성한 요청 HTTP 메시지 파싱
- HTTP 응답 메시지 생성
- TCP/IP에 응답 전달, 소켓 종료
(비즈니스 로직을 제외한 모든 프로세스들을 처리)

@ServletComponentScan

스프링 부트에서 서블릿을 직접 등록해서 사용할 수 있도록 지원하는 어노테이션
(@WebServlet 등의 어노테이션을 스캔하여 서블릿 컨테이너에 등록한다)

@WebServlet(name = "tempServlet", urlPatterns = "/hello")

- name : 서블릿 이름
- urlPatterns : URL 매핑

HTTP 요청을 통해 매핑된 URL이 호출되면 서블릿 컨테이너는 아래 service 메서드를 실행한다.

@WebServlet(name = "tempServlet", urlPatterns = "/hello")
public class TempServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) {
    	/* ... */
    }
}

* HttpServlet의 상속이 필요하다
* @Override 하는 함수는 protected void service이다. 주의할 것

서블릿 컨테이너의 동작 방식

HttpServletRequest

서블릿은 편리한 사용을 위해 HTTP 요청 메시지를 파싱하여 그 결과를 HttpServletRequest 객체에 담아서 개발자에게 제공한다

부가 기능

임시 저장소 기능(HTTP 요청이 시작부터 끝날 때 까지 유지된다)

- 저장 : request.setAttribute(name, value)
- 조회 : request.getAttribute(name)

세션 관리 기능

- request.getSession(create : true)
* HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해하는 것이 중요

HTTP Request 메시지를 통한 데이터 전달 방식

GET 쿼리 파라미터

- ? : 시작 / & : 구분
- /url?name=test&age=99
- URL의 쿼리 파라미터에 데이터를 포함해서 전달
- 데이터 조회

//단일 파라미터 조회
String name = request.getParameter("name");

//파라미터 이름들 모두 조회
Enumeration<String> parameterNames = request.getParameterNames();
//참고
request.getParameterNames().asIterator()
	.forEachRemaining(paramName -> System.out.println(paramName +
	"=" + request.getParameter(paramName)));


//파라미터를 Map으로 조회
Map<String, String[]> parameterMap = request.getParameterMap(); 

//복수 파라미터 조회
String[] names = request.getParameterValues("name");

POST - HTML Form

- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파라미터 형식으로 전달
ex) name=test&age=99
- 데이터 조회는 GET 쿼리 파라미터와 동일하다

HTTP Message Body에 데이터를 직접 담아서 요청

- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
- 데이터 조회는 InputStream을 사용해서 직접 읽을 수 있다

ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);

- 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);
	JsonData jsonData = objectMapper.readValue(messageBody, JsonData.class);
	System.out.println("jsonData.name = " + jsonData.getName());
	System.out.println("jsonData.age = " + jsonData.getAge());	
}

HttpServletResponse

HTTP 응답 메시지를 편하게 생성하는 객체

- HTTP 응답코드 지정
- 헤더 생성
- 바디 생성
- 기본 사용법

// 응답코드 지정 
response.setStatus(HttpServletResponse.SC_OK);

// Header 설정
response.setHeader("Content-Type", "text/plain;charset=utf-8");
// 아래와 같이 설정도 가능하다
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");

// 임의 Header 설정
response.setHeader("temp-header","test");

// 쿠키 설정 기능
Cookie cookie = new Cookie("myCookie", "test");
cookie.setMaxAge(3600); // Second
response.addCookie(cookie);

// redirect
//response.setStatus(HttpServletResponse.SC_FOUND); //302
//response.setHeader("Location", "/basic/hello-form.html");
response.sendRedirect("/basic/hello-form.html");

- HTML 응답

response.setContentType("text/html");
response.setCharacterEncoding("utf-8");

PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>Test</div>");
writer.println("</body>");
writer.println("</html>");

- API JSON 응답

response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8");

JsonData data = new JsonData();
data.setName("Song");
data.setAge(99);

String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);

* application/json 은 스펙상 utf-8 형식을 사용하도록 정의되어 있다
  그래서 스펙에서 charset=utf-8과 같은 추가 파라미터를 지원하지 않는다
  따라서 application/json 이라고만 사용해야지 application/json;charset=utf-8 이라고 전달하는 것은
  의미 없는 파라미터를 추가한 것이 된다