[Spring Web MVC] 서블릿과 HTTP 통신
서블릿을 직접 사용해보자.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("start!");
}
}
@ServletComponentScan 애너테이션으로 스프링이 서블릿을 등록해서 사용할 수 있도록 하자.
@WebServlet 애너테이션은 서블릿 이름과 URL 매핑을 지정한다.
스프링이 내장 톰캣 서버를 실행한다.
서버가 실행되면 애너테이션 기반으로 서블릿을 찾아 모두 생성해준다. (init)
클라이언트의 요청이 들어오면 WAS는 request response 객체를 만들고 서블릿을 호출한다.
helloServlet은 내부의 service 메서드를 호출해 작업을 수행한다.
여기서 req.getParameter() , res.setContentType() 등 여러 req와 res 객체의 메서드를 사용해 클라이언트의 요청 메세지를 해석해서 읽거나 클라이언트에게 전달할 응답 메세지를 조작할 수 있다.
HTTP 요청 메세지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법에는 크게 3가지가 있다.
1. GET - 쿼리 파라미터
url에 쿼리 파라미터를 추가해서 전달한다.
url에 "?" 와 "&" 를 추가하는 방식으로 사용한다.
2. POST - HTML Form
폼을 통해 전송 버튼을 누르면 웹 브라우저가 알아서 HTTP 요청 메세지를 생성한다.
메세지 바디에 쿼리 파라미터 형식으로 데이터를 전달해 조회할 때는 GET 방식과 호환된다.
3. HTTP message body
메세지 바디에 데이터를 직접 담아서 전송한다.
HTTP API에서 주로 사용하고, 주로 JSON 타입을 사용한다.
이 때는 POST PUT PATCH 세 가지 메서드가 사용된다.
@WebServlet(name = "zz", 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)));
// 단일 파라미터 조회
req.getParameter("username");
// 키 값은 중복이 가능하다
String[] usernames = req.getParameterValues("username");
for (String name : usernames) {
System.out.println("username=" + name);
}
}
}
(애너테이션에서 name은 서블릿을 구별하기 위해 사용되고, 설정하지 않으면 해당 클래스의 이름으로 사용한다.)
서블릿에서 요청 메세지의 쿼리 파라미터를 읽어오는 예시이다.
쿼리에서 키 값은 중복이 가능한데, 이 경우 getParameterValues() 메서드를 통해 해당 키 값을 가지는 모든 요소를 가져와야 한다.
<form action="/request-param" method="post">
위와 같이 HTML 폼을 만들고 전송하면 웹 브라우저는 /request-param url으로 HTTP 요청 메세지를 보낸다.
/request-param 으로 요청 메세지가 도착하면 해당 url으로 매핑된 서블릿이 실행된다.
content-type 은 HTTP 메세지 바디의 데이터 형식을 지정한다.
쿼리 파라미터를 사용할 때는 url에 정보를 추가하는 방식으로 진행해 모두 문자열로 인식되기에 content-type이 없지만, 폼을 사용할 때는 HTTP 메세지 바디에 해당 데이터를 포함해서 보내기 때문에 content-type을 꼭 지정해야 한다.
몇 가지 content-type에 대해 살펴보자.
1. aplication/x-www-form-urlencoded
HTML 폼의 기본 Content-Type으로, 키-값 쌍으로 URL 인코딩돼 전송된다.
쿼리 파라미터를 통해 데이터를 전송할 때와 데이터의 형식이 같아 req.getParamter() 메서드로 값에 접근할 수 있다.
2. multipart/form-data
파일이나 바이너리 데이터를 전송할 때 사용된다.
각 필드는 구분자로 분리된다.
3. application/json
JSON 데이터를 전송할 때 사용된다.
이 외에도 text/plain으로 일반 텍스트를, text/html으로 HTML 문서를 나타내는 등 여러 가지 content-type이 있으니 그때 그때 찾아보자.
HTTP 요청에서 content-type 헤더는 클라이언트가 서버에게 보내는 본문의 미디어타입을 나타내고, 서버는 해당 값을 통해 본문의 데이터를 어떻게 해석할 지 결정한다.
HTTP 응답에서 content-type 헤더는 반대로 서버가 클라이언트에게 반환하는 본문의 미디어 타입을 나타낸다.
클라이언트는 본문의 데이터를 어떻게 해석할 지 결정한다.
@WebServlet(name = "za", urlPatterns = "request-body-string")
public class RequestBodyStringServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream inputStream = req.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
System.out.println("messageBody = " + messageBody);
resp.getWriter().write("accept!");
}
}
HTTP 메세지 바디에 단순 텍스트 데이터를 담아서 전송하는 예시이다.
메세지 바디의 데이터를 InputStream을 사용해서 바이트코드로 반환하고, copyToString 메서드로 문자열로 변환해줬다. (바이트 - 문자열 변환에는 Charset을 지정해 줘야 한다.)
@WebServlet(name = "zzasdf", 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 messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
objectMapper.readValue(messageBody, HelloData.class);
}
}
HTTP 메서지 바디를 통해서 클라이언트가 데이터를 전송할 때는 보통 JSON 타입을 사용한다.
일반 텍스트를 읽어올 때와 같이 inputSream, copyToString을 메서드를 사용하지만, 이후 JSON 객체를 자바 객체로 변환하기 위해 Jackson, Gson 등 변환 라이브러리를 사용해야 한다.
스프링 MVC를 사용하면 기본으로 Jackson 라이브러리가 ObjectMapper 를 통해 제공된다.
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class HelloData {
private String username;
private int age;
}
ObjectMapper를 통해 문자열으로 바꾼 JSON 객체를 자바 객체로 변환했다.
@WebServlet(name = "ad", urlPatterns = "/response-header")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// status line
resp.setStatus(HttpServletResponse.SC_OK);
// response header
resp.setHeader("Content-Type", "text/plain;charset=utf-8");
resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
resp.setHeader("Pragma", "no-cache"); // past cover
resp.setHeader("temp-header-zz", "hi");
PrintWriter writer = resp.getWriter();
writer.println("ok");
}
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);
}
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");
}
}
service 메서드의 인자로 받는 resp 객체로 서버에서 클라이언트로 보내는 응답 메세지를 보낼 때 내용을 조작할 수 있다.
여러 가지 편의 메서드를 제공하니 편하게 사용하자.
'Spring > Spring Web MVC' 카테고리의 다른 글
[Spring Web MVC] Spring MVC (0) | 2022.08.16 |
---|---|
[Spring Web MVC] Adaptor (0) | 2022.08.16 |
[Spring Web MVC] Model (0) | 2022.08.15 |
[Spring Web MVC] Front Controller (0) | 2022.08.15 |
[Spring Web MVC] 웹 애플리케이션 (0) | 2022.08.13 |
댓글
이 글 공유하기
다른 글
-
[Spring Web MVC] Adaptor
[Spring Web MVC] Adaptor
2022.08.16 -
[Spring Web MVC] Model
[Spring Web MVC] Model
2022.08.15 -
[Spring Web MVC] Front Controller
[Spring Web MVC] Front Controller
2022.08.15 -
[Spring Web MVC] 웹 애플리케이션
[Spring Web MVC] 웹 애플리케이션
2022.08.13