개요 목적
Java로 직접 구현하는 HTTP Sever 해당 프로젝트에서는 http 관련 클래스 없이 java 코드만으로 HTTP 프로토콜 서버를 구현했다. 그러다보니 Client Request Message를 일일이 분석해서 비지니스 코드에 적용해야 하고 그 결과를 Response 형식에 맞춰서 보내줘야 하는 동작을 반복해야 했다.
이러한 HTTP 서버를 만들 때 반복되는 동작들을 일관적으로 대신 처리해주는 것이 WAS에서 사용하는 서블릿이다. 자바는 HttpServlet 인터페이스를 사용하여 HTTP 서버를 비지니스 로직에만 집중하며 만들 수 있다.
이번 시간에는 Spring에서도 사용하는 서블릿에 대한 이해와 HttpServlet의 기본 사용법을 알아보겠다.
서블릿이란
서블릿은 개발자가 HTTP 스펙 사용을 매우 편리하게 도와준다. url이 들어오면 urlPatterns 을 지정한 컨트롤러가 동작이 된다. 해당 메소드 안에서 HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest와 HTTP 응답 정보를 편리하게 제공할 수 있는 HttpServletResponse를 사용해서 편리하게 비지니스 로직을 작성할 수 있다.
@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response){
//애플리케이션 로직
}
톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너가 부른다.
HTTP 요청이 오면 서블릿 컨테이너가 제공하는 Reqeust 객체에 담긴 HTTP 요청 정보를 사용할 수 있고, 결과 값을 Response 객체에 담으면 HTTP 응답 정보를 만들어준다.
HttpServletRequest 기본 사용법
서블릿은 HTTP 요청 메세지를 편리하게 사용할 수 있도록 정보를 파싱하여 HttpServletRequest 객체에 담아서 제공한다.
- Start Line(HTTP 메소드, URL, 쿼리 스트링, 스키마, 프로토콜)
- Header(각종 Client가 작성한 header 정보들)
- Body( form 파라미터 형식 조회, message body 데이터 직접 조회)
Start Line 정보 조회
//이런식으로 HttpServletRequest 객체를 받아서 그 안에 있는 메소드로
//파싱한 HTTP 정보를 얻을 수 있다.
private void printStartLine(HttpServletRequest request) {
System.out.println("request.getMethod() = " + request.getMethod());
}
request.getMethod() = GET
request.getProtocol() = HTTP/1.1
request.getScheme() = http
request.getRequestURL() = <http://localhost:8080/request-header>
request.getRequestURI() = /request-header
request.getQueryString() = username=hello
request.isSecure() = false
Header 정보 조회
@WebServlet(name = "requestHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//모든 헤더 조회
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + ": " + headerName));
//Host 헤더 정보
System.out.println("request.getServerName() = " + request.getServerName());
System.out.println("request.getServerPort() = " + request.getServerPort());
//Accept-Language 편의 조회
request.getLocales().asIterator()
.forEachRemaining(locale -> System.out.println("locale = " + locale));
System.out.println("request.getLocale() = " + request.getLocale());
//Cookie 편의 조회
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println(cookie.getName() + ": " + cookie.getValue());
}
}
//Content 편의 조회
System.out.println("request.getContentType() = " + request.getContentType());
System.out.println("request.getContentLength() = " + request.getContentLength());
System.out.println("request.getCharacterEncoding() = " + request.getCharacterEncoding());
//Remote 정보
System.out.println("request.getRemoteHost() = " + request.getRemoteHost());
System.out.println("request.getRemoteAddr() = " + request.getRemoteAddr());
System.out.println("request.getRemotePort() = " + request.getRemotePort());
//Locale 정보
System.out.println("request.getLocalName() = " + request.getLocalName());
System.out.println("request.getLocalAddr() = " + request.getLocalAddr());
System.out.println("request.getLocalPort() = " + request.getLocalPort());
}
}
요청 데이터 조회
<파라미터 요청 조회>
@WebServlet(name = "requestParamServlet", urlPatterns = "/request-param")
public class RequestParamServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//파라미터 데이터 조회
//1 전체 파라미터
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> System.out.println(paramName + "=" + request.getParameter(paramName)));
//2 단일 파라미터 조회
String username = request.getParameter("username");
String age = request.getParameter("age");
//3 이름이 같은 파라미터 조회
String[] usernames = request.getParameterValues("username");
}
}
<message Body 직접 조회>
@WebServlet(name = "requestBodyStringServlet", urlPatterns = "/request-body")
public class RequestBodyStringServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1 String 타입 조회
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
//2 json 타입 조회
HelloData helloData = objectMapper.readValue(messageBody, HelloData.class);
}
}
HttpServletResponse 기본 사용법
HttpServletResponse를 사용해서 HTTP 응답코드 지정, 헤더 생성, 바디 생성을 손쉽게 할 수 있다.
@WebServlet(name = "responseHeaderServlet", urlPatterns = "/response")
public class ResponseHeaderServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1 응답 코드 지정하기
response.setStatus(HttpServletResponse.SC_OK);
//2 헤더 지정하기
response.setHeader("Content-Type", "text/plain;charset=utf-8");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("my-header", "hello");
//3 json response body 지정하기
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("utf-8");
HelloData data = new HelloData();
data.setUsername("kim");
data.setAge(20);
String result = objectMapper.writeValueAsString(data);
response.getWriter().write(result);
}
}
'Web Sever 개발과 CS 기초 > 스프링' 카테고리의 다른 글
테스트 결과를 ELK 사용하여 기록 남기기(Logstash Json parsing) (0) | 2023.05.16 |
---|---|
백엔드 서버 API doc 작성과 Springdoc 자동 구성하기 (0) | 2023.05.16 |
Java로 직접 구현하는 HTTP Server (0) | 2023.05.13 |
Security-JWT 토큰을 이용한 OAuth2(Google) 인가 서비스 구현 (0) | 2023.05.11 |
스프링 알림 기능 - Spring Data JPA DB 구현 (0) | 2023.05.11 |