02. 서블릿
#Spring/MVC
스프링 부트 서블릿 환경 구성
스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 @ServletComponentScan
을 지원ㅇ한다.
서블릿 등록
인텔리제이에서 ctrl + o로 오버라이딩 할 수 있는데, 자물쇠 잠겨있는 service(protected)를 오버라이딩해주자. 서블릿이 호출되면, 서비스 메서드가 호출된다.
@WebServlet
서블릿 애노테이션- name: 서블릿 이름
- urlPatterns: URL 매핑
HTTP 요청을 통해 매핑된 URL이 호출되면 서블릿 컨테이너는 다음 메서드를 실행한다.protected void service(HttpServletRequest request, HttpServletResponse response)
HttpServletRequest, HttpServletResponse 얘내들은 인터페이스다. Tomcat, Jetty, Undertow 등등 WAS 서버들이 이 서플릿 표준 스펙을 구현하는 거다. 콘솔에 찍힌 것들이 구현체다.
쿼리 파라미터 값을 request.getParameter("파라미터이름")
을 통해 꺼내 사용할 수 있다.
response.setContentType("text/plain");
Http 헤더 컨텐츠 타입을 정해준다.
response.setCharacterEncoding("utf-8");
Http 헤더에 인코딩 정보를 알려준다
response.getWriter().write("heelo" + username);
Http 메시지 바디에 데이터가 들어간다.
Content-Length 같은 나머지 정보는 톰켓 서버가 자동으로 만들어준다.
HTTP 요청 메시지 로그 확인
- 설정 파일
application.properties
에 아래 내용을 추가:
logging.level.org.apache.coyote.http11=trace
이 기능은 실제 운영서버에 추가할 시 성능 저하가 발생할 수 있으므로 개발 단계에서만 사용하자.
스프링 부트를 실행하면 부트가 내장 톰켓 서버를 띄운다. 톰캣 서버 내부에는 서블릿 컨테이너 기능이 있다.
서블릿 컨테이너에서 서블릿을 다 생성을 해주고, 우리가 만들었던 HelloServlet도 생성이 된다.
서블릿 컨테이너 동작 방식
클라이언트가 HTTP 메시지를 만들어서 던져주면, 서버는 request, response 객체를 만들어서 싱글톤 객체인 helloServlet을 호출해준다. 서비스 메서드를 호출하면서 request, response 를 넘겨주는 것이다.
필요한 작업을 하고(ex. response에 contenttype 지정), 서블릿이 종료된다. 서블릿이 종료되고 나가면서 WAS 서버가 이 response 정보를 가지고 HTTP 응답 메시지를 만들어서 반환해준다. 부가정보는 WAS가 자동으로 생성해준다.
HttpServletRequest 역할
서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱하여 HttpServletReqeust
객체에 담아서 제공한다.
- START LINE
- HTTP 메소드
- URL
- 쿼리 스트링
- 스키마, 프로토콜
- 헤더
- 헤더 조회
- 바디
- form 파라미터 형식 조회
- message body 데이터 직접 조회
다 파싱해준다.
임시 저장소 기능 해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능
- 저장:
request.setAttribute(name, value)
- 조회:
request.getAttribute(name)
세션 관리 기능
request.getSession(create: true)
Start-Line 조회
System.out.println("request.getMethod() = " + request.getMethod());
System.out.println("request.getRequestURL() = " + request.getRequestURL());
System.out.println("request.getRequestURI() = " + request.getRequestURI());
System.out.println("request.getQueryString() = " + request.getQueryString());
이런식으로 get메서드를 통해 조회할 수 있다.
헤더 조회
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + ": " + request.getHeader(headerName)));
이렇게 하면 원하는 것만 뽑아서 못본다. request.getServerName()
request.getServerPort()
를 통해서 호스트를 편하게 조회할 수 있고,
Accept-Language를 조회하기 위해선 아래와 같이 조회할 수 있다.
request.getLocales().asIterator()
.forEachRemaining(locale -> System.out.println("locale = " +
locale));
System.out.println("request.getLocale() = " + request.getLocale());
request.getLocale()
: 클라이언트의 가중치가 가장 높은 Accept-language를 선택
쿠키를 편하게 조회하기 위해서는request.getContentType()
request.getContentLength()
request.getCharacterEncoding()
를 사용할 수 있다.
바디에 값이 없으면 -1이나 null 값이 된다.
이외에도
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()); //
요런 기능들을 제공한다.
특정 메서드를 지정하지 않고 원하는 헤더 정보를 꺼내려면(e.g host)
request.getHeader(“host”) 요런 식으로 원하는 헤더 이름을 적어주면 그 값을 꺼낼 수 있다.
HTTP 요청 데이터
HTTP 요청 메시지를 통해 클라이언트에서 서버로 데이터를 전달하는 방법에는 크게 3가지가 있다.
- GET - 쿼리 파라미터
- URL 형식:
/url?username=hello&age=20
- 쿼리 파라미터는 URL에 다음과 같이
?
를 시작으로 보낼 수 있다. 추가 파라미터는&
로 구분한다.
- URL 형식:
HttpServletRequest의 다음 메서드를 통해 쿼리 파라미터를 조회할 수 있다.
String username = request.getParameter("username"); // 단일 파라미터 조회
Enumeration<String> parameterNames = request.getParameterNames(); // 파라미터 이름들 모두 조회
Map<String, String[]> parameterMap = request.getParameterMap(); // 파라미터를 Map으로 조회
String[] usernames = request.getParameterValues("username"); // 복수 파라미터 조회
http://localhost:8080/request-param?username=hello&age=20&username=hello2
이런식으로 이름이 같은 복수 파라미터도 가능하다.
request.getParameter()
는 하나의 파라미터 이름에 대해서 단 하나의 값만 있을 때 사용해야 한다. 지금처럼 중복일 때는request.getParameterValues()
를 사용해야 한다.
- POST - HTML Form
- content-type: application/x-www-form-urlencoded
- 메시지 바디에 쿼리 파리미터 형식으로 전달
application/x-www-form-urlencoded
형식은 GET에서 살펴본 쿼리 파라미터 형식과 같다.
- content-type: application/x-www-form-urlencoded
request.getParameter()
는 GET URL 쿼리 파라미터 형식도 지원하고, POST HTML Form 형식도 둘 다 지원한다.
- HTTP message body에 데이터를 직접 담아서 요청
- HTTP API에서 주로 사용, JSON, XML, TEXT
- JSON, XML… 도 결국에는 문자열이다.
단순 문자열: HTTP 메시지 바디의 데이터를 InputStream을 사용해서 직접 읽을 수 있다.
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
JSON 형식
JSON 형식 데이터를 자바 객체로 변환하여 받는다.
스프링 MVC가 제공하는 ObjectMapper를 통해 Json 문법의 InputStream을 객체로 변환할 수 있다.
private ObjectMapper objectMapper = new ObjectMapper();
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
HTTP 응답 데이터
크게 3가지 내용을 담아서 전달한다.
- HTTP 응답코드 지정
- 헤더 생성
- 바디 생성
HttpServletResponse는 이를 편리하게 지정할 수 있도록 메서드를 제공한다.
Status-Line
response.setStatus(HttpServletResponse.SC_OK); // 200
기본적인 헤더 설정 방법
response.setHeader("Content-Type", "text/plain;charset=utf-8");
기본적으로는 헤더 종류, 값을 일일히 지정해야 한다. 하지만 편의 메서드를 제공한다.
참고
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
캐시를 완전히 무효화하겠다.
response.setHeader("Pragma", "no-cache");
과거 버전까지 캐시를 없앤다.
Content 편의 메서드
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
특정 헤더를 설정할 수 있는 메서드가 존재해서 그걸 사용하면 된다.
기본으로 보낼 때는 Content-Length가 필요하다. 생략하면 content-body에 있는 걸 자동으로 계산해준다.
쿠키 편의 메서드
Cookie cookie = new Cookie("myCookie", "good");
cookie.setMaxAge(600); // 600초
response.addCookie(cookie);
redirect 편의 메서드
response.sendRedirect("/basic/hello-form.html");
원래는 상태코드를 지정하고, Location 헤더에 url을 적어줘야 하지만,
sendRedirect 메서드로 url만 적어주면 상태코드까지 설정된다.
메시지 바디
// [message body]
PrintWriter writer = response.getWriter();
writer.println("ok");
response.getWriter나 response.getInputStream으로 가져와서 값을 넣어주면 값이 메시지 바디에 넣어지게 된다.
HTTP 응답 데이터 종류
HTTP 응답 메시지는 주로 다음 내용을 담아서 전달한다.
- 단순 텍스트 응답
- 앞에서 살펴봄 (
writer.println("ok");
)
- 앞에서 살펴봄 (
- HTML 응답
- 웹 브라우저에 HTML을 반환
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<body>");
writer.println(" <div>안녕?</div>");
writer.println("</body>");
writer.println("</html>");
서블릿으로 html을 렌더링할 때는 이렇게 직접 작성해야 한다. 동적으로 html을 생성할 수도 있다.
- HTTP API - MessageBody JSON 응답
- JSON 데이터 반환
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8"); // 사실은 필요 없다.
HelloData data = new HelloData();
data.setUsername("kim");
data.setAge(20);
// {"username":"kim","age":20}
String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);
json도 문자열이기 때문에 objectMapper를 통해 json 문법 문자열로 변환한다.
application/json
은 스펙상 UTF-8 형식을 사용하도록 정의되어 있다.
따라서 application/json;charset=utf-8
이라고 전달하는 것은 의미 없는 파라미터를 추가한 것이다. response.getWriter()
를 사용하면 추가 파라미터가 자동으로 추가될 수 있다.
'Spring > MVC' 카테고리의 다른 글
[Spring MVC] 04. MVC 프레임워크 만들기 (0) | 2024.11.20 |
---|---|
[Spring MVC] 03. 서블릿, JSP, MVC 패턴 (0) | 2024.11.19 |
[Spring MVC] 01. Web Application의 이해 (0) | 2024.11.19 |
[Spring/입문] 07. AOP (0) | 2024.05.13 |
[Spring/입문] 06. 스프링 DB 접근 기술 (0) | 2024.05.13 |