서블릿이란 개발자가 HTTP 메세지로 통신할때 필요한 기본 과정들이 존재하는데 그 과정을 간소화 시켜주고 개발자는 핵심 비지니스 로직에 집중할 수 있게 도와주는 기능을 말한다.
서블릿이 없을땐 위의 삭제된 과정들을 개발자가 직접 코드로 만들어야하는데 우리는 서블릿을 사용함으로 이 작업들을 축소하고 핵심 비지니스 로직에만 집중할 수 있다. 그렇다면 이 서블릿은 누가 제공하는걸까?
서블릿은 was에서 HTTP 메세지를 받았을 때 서블릿 컨테이너를 통해 개발자가 요청과 응답을 사용하기 쉽게 만들어준다.
그럼 was에서 제공해주는 서블릿 컨테이너가 없다고 가정하고 코드로 한번 서블릿의 구조를 살펴보자
servlet을 직접 구현할거지만 정말 옛날처럼 어노테이션의 도움 없이 스프링의 도움 없이는 아니고 간단하게 구현해보려고 한다.
logging.level.org.apache.coyote.http11=debug
그 전에 application.properties 파일에 다음과 같은 설정을 추가해주자. 이 설정을 하게 되면 웹에서 요청과 응답에 대한 상세 값들을 로그로 확인할 수 있다.
스프링 부트로 프로젝트를 생성했다고 가정하고 시작하겠다.
제일 먼저 스프링 부트에서 서블릿을 내가 직접 등록해서 사용하겠다 라고 알려줘야한다.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan //서블릿 자동 등록
@SpringBootApplication
public class ServletApplication {
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class, args);
}
}
@ServletComponentScan을 통해 우리가 등록하는 Servlet을 인식해 달라고 설정한다.
그 다음 HelloServlet이란 파일을 servlet>basic 아래에 생성해주고 패키지 구조는 사용자가 알아서 설정해도 된다!
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// /helo로 들어왔을때 해당 servlet이 실행됨
@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("req = " + request);
System.out.println("resp = " + 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은 서블릿의 이름, urlPattern은 해당 url로 들어왔을때 servlet이 자동으로 실행되도록 설정해준다. 이 상태로 spring을 띄워보고 http://localhost:8080/hello 로 접속해보면
다음과 같이 우리가 실행하도록 만든 코드들이 실행된다. username은 null로 나오는데 이 부분은 우리가 파라미터를 던지지 않았기 때문이다. 파라미터는 get방식으로
http://localhost:8080/hello?username=test
이렇게 해주면 정상적으로 나올것이다.
이렇게 정상적으로 처리되었고 위에 보이는 내용들은 우리가 아까 설정한 http 메세지를 콘솔에 노출시키게 해놨기 때문에 확인할 수 있는 내용들이다. HTTP 스펙에 대한 부분을 공부했다면 다음 내용은 어느정도 이해할 수 있을것이고 이해하지 못하겠다면 HTTP에 대해 공부 해보는것을 추천한다.
https://ililil9482.tistory.com/120
hello>servlet>basic>request 패키지를 만들고 RequestHeaderServlet을 만들어 header에 담겨오는 내용을 서블릿에서 파싱해보려고 한다.
@WebServlet(name = "reqeustHeaderServlet", urlPatterns = "/request-header")
public class RequestHeaderServlet extends HttpServlet {
}
위에 만든 서블릿과 동일하게 서블릿을 만들고
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
printStartLine(request);
printHeaders(request);
printHeaderUtils(request);
printEtc(request);
}
private void printStartLine(HttpServletRequest request) {
System.out.println("--- REQUEST-LINE - start ---");
System.out.println("request.getMethod() = " + request.getMethod()); //GET
System.out.println("request.getProtocal() = " + request.getProtocol()); //HTTP/1.1
System.out.println("request.getScheme() = " + request.getScheme()); //http
// http://localhost:8080/request-header
System.out.println("request.getRequestURL() = " + request.getRequestURL());
// /request-test
System.out.println("request.getRequestURI() = " + request.getRequestURI());
//username=hi
System.out.println("request.getQueryString() = " + request.getQueryString());
System.out.println("request.isSecure() = " + request.isSecure()); //https 사용 유무
System.out.println("--- REQUEST-LINE - end ---");
System.out.println();
}
//Header 모든 정보
private void printHeaders(HttpServletRequest request) {
System.out.println("--- Headers - start ---");
/*Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println(headerName + ": " + request.getHeader(headerName));
}*/
request.getHeaderNames().asIterator().forEachRemaining(headerName -> System.out.println(headerName + ": "+headerName));
request.getHeaderNames().asIterator()
.forEachRemaining(headerName -> System.out.println(headerName + ":" + request.getHeader(headerName)));
System.out.println("--- Headers - end ---");
System.out.println();
}
//Header 편리한 조회
private void printHeaderUtils(HttpServletRequest request) {
System.out.println("--- Header 편의 조회 start ---");
System.out.println("[Host 편의 조회]");
System.out.println("request.getServerName() = " +
request.getServerName()); //Host 헤더
System.out.println("request.getServerPort() = " +
request.getServerPort()); //Host 헤더
System.out.println();
System.out.println("[Accept-Language 편의 조회]");
request.getLocales().asIterator()
.forEachRemaining(locale -> System.out.println("locale = " +
locale));
System.out.println("request.getLocale() = " + request.getLocale());
System.out.println();
System.out.println("[cookie 편의 조회]");
if (request.getCookies() != null) {
for (Cookie cookie : request.getCookies()) {
System.out.println(cookie.getName() + ": " + cookie.getValue());
}
}
System.out.println();
System.out.println("[Content 편의 조회]");
System.out.println("request.getContentType() = " +
request.getContentType());
System.out.println("request.getContentLength() = " +request.getContentLength());
System.out.println("request.getCharacterEncoding() = " +
request.getCharacterEncoding());
System.out.println("--- Header 편의 조회 end ---");
System.out.println();
}
//기타 정보
private void printEtc(HttpServletRequest request) {
System.out.println("--- 기타 조회 start ---");
System.out.println("[Remote 정보]");
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()); //
System.out.println("--- 기타 조회 end ---");
System.out.println();
}
서블릿에 위의 메서드들로 요청 결과를 콘솔에서 확인해볼 수 있다. 콘솔에 찍히는 내용이 워낙 많아서 직접 코드를 실행하여 확인해 보자!
참고로 body에 담기는 정보를 확인하기 위해서는 postman을 통해 post요청시 body에 내용을 담아서 보내야 확인이 가능하다!