서블릿
스프링 부트 환경에서 서블릿 등록하고 사용해 보자.
참고
서블릿은 톰캣 같은 웹 애플리케이션 서버를 직접 설치하고, 그, 위에 서블릿 코드를 클래스 파일로 빌드해서 올린 다음, 톰캣 서버를 실행하면 된다. 하지만 이 과정은 매우 번거롭다. 스프링 부트는 톰캣 서버를 내장하고 있으므로, 톰캣 서버 설치 없이 편리하게 서블릿 코드를 실행할 수 있다.
스프링 부트 서블릿 환경 구성
@ServletComponentScan
스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 @ServletComponentScan을 지원한다. 다음과 같이 추가하자.
@ServletComponentScan//서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
서블릿 등록하기
@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);
}
}
@WebServlet 서블릿 애노테이션
- name: 서블릿 이름
- urlPatterns: URL 매핑
HTTP 요청을 통해 매핑된 URL이 호출되면 서블릿 컨테이너는 다음 메서드를 실행한다.
protected void service(HttpServletRequest request, HttpServletResponse response)
서블릿 컨테이너 동작 방식 설명
내장 톰캣 서버 생성
스프링 부트가 실행되면 내장 톰켓 서버를 생성한다.
내장 톰켓 서버는 내부에 서블릿 컨테이너 기능을 가지고 있다.
서블릿 컨테이너 기능을 통해 서블릿을 생성한다.
HTTP 요청, HTTP 응답 메시지

웹 애플리케이션 서버의 요청 응답 구조
서블릿 컨테이너가 HTTP 요청 메시지를 기반으로 request, response 객체를 생성한다.
그다음 싱글톤으로 떠 있는 서블릿(helloServlet)을 호출하면서 서블릿에 request와 response를 넘겨준다.
서블릿에서는 response에 응답 data를 넣고 서블릿 컨테이너로 보내고 종료된다.
서블릿 컨테이너는 response 객체 정보로 HTTP 응답을 생성하고 웹 브라우저에 전송한다.
WAS는 여러 가지 역할이 존재한다.
- HTTP 요청 메시지를 연결하고 받아들이는 웹 서버의 역할
- HttpServletRequest, HttpServletReponse를 생성하고, 우리가 만든 서블릿을 호출하는 서블릿 컨테이너의 역할
- 그리고 서블릿 컨테이너는 우리가 만든 서블릿을 관리하는 역할
그림에서는 WAS와 서블릿 컨테이너가 따로 나눠져 보이지만 실상은 WAS = HTTP 통신 + 서블릿 컨테이너이다.
WAS는 모든 기능이 통합되어서 제공된다고 생각하면 된다.
서블릿 컨테이너의 역할을 좀 더 강조한다고, 그림을 나누어 두었다고 보면 된다.
참고
HTTP 응답에서 Content-Length는 웹 애플리케이션 서버가 자동으로 생성해 준다.
HttpServletRequest - 개요
HttpServletRequest 역할
HTTP 요청 메시지를 개발자가 직접 파싱 해서 사용해도 되지만, 매우 불편할 것이다.
서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱 한다..
그리고 그 결과를 HttpServletRequest 객체에 담아서 제공한다.
HttpServletRequest를 사용하면 다음과 같은 HTTP 요청 메시지를 편리하게 조회할 수 있다.
HTTP 요청 메시지
POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20
- START LINE
- HTTP 메소드
- URL
- 쿼리 스트링
- 스키마, 프로토콜 헤더
- 헤더
- 헤더 조회
- 바디
- form 파라미터 형식 조회
- message body 데이터 직접 조회
HttpServletRequest 객체는 추가로 여러 가지 부가기능도 함께 제공한다.
임시 저장소 기능
- 해당 HTTP 요청이 시작부터 끝날 때 까지 유 지되는 임시 저장소 기능
- 저장: request.setAttribute(name, value)
- 조회: request.getAttribute(name)
세션 관리 기능
- request.getSession(create: true)
HttpServletRequest, HttpServletResponse를 사용할 때 가장 중요한 점은 이 객체들이 HTTP 요청 메시지, HTTP 응답 메시지를 편리하게 사용하도록 도와주는 객체라는 점이다. 따라서 이 기능에 대해서 깊이 있는 이해를 하려면 HTTP 스펙이 제공하는 요청, 응답 메시지 자체를 이해해야 한다.
HTTP 요청 데이터 - 개요
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법을 알아보자.
클라이언트는 서버로 메시지를 보낼때 주로 다음 3가지 방법을 사용한다.
GET - 쿼리 파라미터
- /url?username=hello&age=20
- 메시지 바디 없이, URL의 쿼리 파라미터에 데이터를 포함해서 전달
- 예) 검색, 필터, 페이징등에서 많이 사용하는 방식
POST - HTML Form
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파리미터 형식으로 전달 username=hello&age=20
- 예) 회원 가입, 상품 주문, HTML Form 사용
HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용 POST, PUT, PATCH
POST- HTML Form 예시
HTTP 요청 데이터 - GET 쿼리 파라미터
다음 데이터를 클라이언트에서 서버로 전송해 보자.
전달 데이터
- username=hello
- age=20
메시지 바디 없이, URL의 쿼리 파라미터를 사용해서 데이터를 전달하자.
예) 검색, 필터, 페이징등에서 많이 사용하는 방식
쿼리 파라미터는 URL에 다음과 같이 ? 를 시작으로 보낼 수 있다. 추가 파라미터는 & 로 구분하면 된다. http://localhost:8080/request-param?username=hello&age=20
서버에서는 HttpServletRequest 가 제공하는 다음 메서드를 통해 쿼리 파라미터를 편리하게 조회할 수 있다.
쿼리 파라미터 조회 메서드
String username = request.getParameter("username");//단일 파라미터 조회 Enumeration<String>parameterNames=request.getParameterNames();//파라미터 이름들 모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); //파라미터를 Map 으로 조회
String[] usernames = request.getParameterValues("username");//복수 파라미터 조회
HTTP 요청 데이터 - POST HTML Form
이번에는 HTML의 Form을 사용해서 클라이언트에서 서버로 데이터를 전송해 보자.
주로 회원 가입, 상품 주문 등에서 사용하는 방식이다.
특징
- content-type: application/x-www-form-urlencoded
- 메시지 body에 data가 들어가기 때문에 content-type이 존재한다.
- 메시지 바디에 쿼리 파리미터 형식으로 데이터를 전달한다. username=hello&age=20
src/main/webapp/basic/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>
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 라 한다.
HTTP 요청 데이터 - API 메시지 바디 - 단순 텍스트
HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT
- 데이터 형식은 주로 JSON 사용
- POST, PUT, PATCH
먼저 가장 단순한 텍스트 메시지를 HTTP 메시지 바디에 담아서 전송하고, 읽어보자.
HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.
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();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
response.getWriter().write("ok");
}
}
참고
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}
/**
* http://localhost:8080/request-body-json
*
* JSON 형식 전송
* content-type: application/json
* message body: {"username": "hello", "age": 20} *
*/
@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");
}
}
JSON 결과를 파싱해서 사용할 수 있는 자바 객체로 변환하려면 Jackson, Gson 같은 JSON 변환 라이브러리를 추가해서 사용해야 한다. 스프링 부트로 Spring MVC를 선택하면 기본으로 Jackson 라이브러리( ObjectMapper )를 함께 제공한다.
HTML form 데이터도 메시지 바디를 통해 전송되므로 직접 읽을 수 있다.
하지만 편리한 파리미터 조회 기능 (request.getParameter(...))을 이미 제공하기 때문에 파라미터 조회 기능을 사용하면 된다.
참고
김영한님의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 강의를 듣고 정리한 내용입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1
'Spring > MVC1' 카테고리의 다른 글
6. 스프링 MVC - 기본 기능 (0) | 2024.08.05 |
---|---|
5. 스프링 MVC - 구조 이해 (0) | 2024.08.05 |
4. MVC 프레임워크 만들기 (0) | 2024.08.02 |
3. 서블릿, JSP, MVC 패턴 (0) | 2024.08.02 |