토비의 스프링부트 정리 (1) - 서블릿과 프런트 컨트롤러로 웹 애플리케이션 만들기
1. 개요
/hello?name=etakyung로 요청하면 Hello etakyung를 돌려주는 작은 웹 애플리케이션을 만들어 보자.
이 예제는 내장 Tomcat과 서블릿을 직접 사용한다. HTTP 요청이 컨트롤러 메서드 호출로 바뀌고, 그 결과가 HTTP 응답으로 전달되는 과정을 이해하는 것이 목표다.
2. 서블릿이란?
서블릿(Servlet) 은 웹 요청을 받아 처리하는 자바 프로그램이다. Tomcat 같은 서블릿 컨테이너가 요청을 받으면, 알맞은 서블릿을 찾아 실행한다.
이 예제의 역할은 다음과 같다.
| 구성 요소 | 역할 |
|---|---|
| Tomcat | HTTP 요청을 받고 서블릿을 실행한다. |
HttpServlet |
요청을 확인하고 응답을 작성한다. |
HelloController |
이름을 받아 인사말을 만든다. |
3. 서버와 서블릿 등록하기
Springboot1Application은 Tomcat을 만들고, 모든 요청을 받을 서블릿을 등록한 뒤 서버를 시작한다.
public static void main(String[] args) {
ServletWebServerFactory serverFactory =
new TomcatServletWebServerFactory();
WebServer webServer = serverFactory.getWebServer(servletContext -> {
HelloController helloController = new HelloController();
servletContext.addServlet("frontcontroller", new HttpServlet() {
@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
if (req.getRequestURI().equals("/hello")
&& req.getMethod().equals(HttpMethod.GET.name())) {
String name = req.getParameter("name");
String ret = helloController.hello(name);
resp.setStatus(HttpStatus.OK.value());
resp.setHeader(HttpHeaders.CONTENT_TYPE,
MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println(ret);
} else {
resp.setStatus(HttpStatus.NOT_FOUND.value());
}
}
}).addMapping("/*");
});
webServer.start();
}
addMapping("/*")은 모든 경로의 요청을 이 서블릿으로 보낸다는 뜻이다. service() 메서드 안에서 요청을 확인하고, 어떤 코드를 실행할지 결정한다.
4. 인사말 만들기
HelloController는 인사말을 만드는 일만 담당한다.
public class HelloController {
public String hello(String name) {
return "Hello " + name;
}
}
예를 들어 hello("etakyung")를 호출하면 Hello etakyung가 반환된다. HTTP 요청을 읽거나 응답을 쓰는 코드를 이 클래스에 넣지 않아, 인사말 로직을 간단하게 유지할 수 있다.
5. 요청 처리 흐름
GET /hello?name=etakyung 요청은 다음 순서로 처리된다.
브라우저
→ Tomcat
→ service()
→ name 파라미터 읽기
→ HelloController 호출
→ "Hello etakyung" 응답
req.getParameter("name")은 URL의 name=etakyung에서 etakyung를 꺼낸다. HelloController가 만든 문자열은 resp.getWriter()를 통해 응답 본문에 작성된다.
응답에는 상태 코드 200과 Content-Type: text/plain도 함께 설정한다. text/plain은 일반 텍스트 응답이라는 뜻이다.
6. 프런트 컨트롤러
모든 요청을 먼저 받는 서블릿을 프런트 컨트롤러(Front Controller) 라고 한다. 이 예제에서는 /*에 연결한 서블릿이 그 역할을 맡는다.
프런트 컨트롤러는 요청 경로를 확인하고, 알맞은 컨트롤러를 호출하며, 공통 기능을 넣을 자리도 제공한다. 예를 들어 인증이나 다국어 처리 같은 코드는 여러 요청에서 반복될 수 있으므로 이 위치에 둘 수 있다.
Spring MVC에서는 DispatcherServlet이 같은 역할을 한다. 이후 @GetMapping 같은 기능을 사용하면 지금 직접 작성한 요청 분기를 Spring MVC가 대신 처리해 준다.
7. 실행하기
애플리케이션을 실행한 뒤 다음 명령으로 확인할 수 있다.
curl -i "http://localhost:8080/hello?name=etakyung"
다음과 같이 200 OK와 Hello etakyung 응답을 확인할 수 있다.
HTTP/1.1 200
Content-Type: text/plain
Hello etakyung
/hello 이외의 경로 또는 GET이 아닌 요청은 현재 코드에서 404 Not Found를 반환한다.
8. 정리
Tomcat은 요청을 받고, 서블릿은 요청을 분석해 HelloController에 일을 맡긴다. 그리고 서블릿이 컨트롤러의 결과를 HTTP 응답으로 작성한다.
이처럼 HTTP 처리와 실제 로직을 나누는 것이 이 예제의 핵심이다. 이 구조를 이해하면 Spring MVC가 요청 처리 코드를 왜 대신해 주는지 자연스럽게 이해할 수 있다.