package org.example;
import org.apache.catalina.startup.Tomcat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
public class WebApplicationServer {
private static final Logger log = LoggerFactory.getLogger(WebApplicationServer.class);
public static void main(String[] args) throws Exception {
String webappDirLocation = "webapps/";
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
log.info("configuring app with basedir: {}", new File("./" + webappDirLocation).getAbsolutePath());
tomcat.start();
tomcat.getServer().await();
}
}
1. WebApplicationServer 클래스 정의 :
public class WebApplicationServer {
private static final Logger log = LoggerFactory.getLogger(WebApplicationServer.class);
WebApplicationServer 클래스를 정의하고 SLF4J를 사용한 로그를 생성하기 위한 Logger객체를 클래스 내부에서 정적 (static)으로 선언한다.
2. 웹 애플리케이션 위치 설정
String webappDirLocation = "webapps/";
웹 애플리케이션의 위치를 나타내는 문자열 변수
3.Tomcat 인스턴스 생성 및 포트 설정
Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
Tomcat 객체를 생성하고, 해당 객체의 포트를 8080으로 설정한다.
4. 웹 애플리케이션 추가
tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
Tomcat에 웹 애플리케이션을 추가하고 루트 컨텍스트 ("/")에는 지정된 디렉토리의 절대 경로를 사용한다.
5. 설정 정보 로깅
log.info("configuring app with basedir: {}", new File("./" + webappDirLocation).getAbsolutePath());
SLF4J를 사용하여 현재 애플리케이션의 설정 정보를 출력한다.
6, Tomcat 서버 시작, 대기
tomcat.start();
tomcat.getServer().await();
Tomcat 서버를 시작하고
서버가 종료될 때까지 대기한다. 이라인은 서버거 계속 실행되도록 하는 역활을 한다.
위코드는 간단한 웹 애플리케이션을 내장 톰캣을 사용하여 실행하는 예제이다 특히, webapps/ 디렉토리에 위치한 웹 애플리케이션을 로컬 웹 서버로 제공하고, 설정 정보를 로그에 출력한다 이코드를 실행하면 설정된 포트 (여기서는 8080)에서 웹 애플리케이션을 확인할 수 있다.
package org.example.mvc;
import org.example.mvc.controller.Controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.RequestDispatcher;
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;
@WebServlet("/")
public class DispatcherServlet extends HttpServlet {
private static Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
private RequestMappingHandlerMaping rehm;
@Override
public void init() throws ServletException {
rehm = new RequestMappingHandlerMaping();
rehm.init();
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("[DispatcherServlet] service started");
try {
Controller handler = rehm.findHandler(request.getRequestURI());
String viewName = handler.handleRequest(request, response);
RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewName);
requestDispatcher.forward(request, response);
} catch (Exception e) {
log.error("exception occured: [{}]", e.getMessage(),e);
throw new ServletException(e);
}
}
}
2. Servlet 클래스 정의 및 Annotation
@WebServlet("/")
public class DispatcherServlet extends HttpServlet {
DispatcherServlet 클래스는 HttpServlet을 상속하며 @WebServlet("/") 어노테이션을 통해 서블릿 매핑을 설정한다
여기서는 루트 경로 ("/") 로 매핑되어 있다.
3. 멤버 변수 및 초기화
private static Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
private RequestMappingHandlerMaping rehm;
Logger 객체와 RequestMappingHandlerMaping 객체를 멤버 변수로 선언한다 Logger 는 SLF4J를 사용하여 로그를 기록하는데 활용되고 RequestMappingHandlerMaping 은 요청을 처리할 핸들러 ( Controller ) 를 찾기 위한 매핑 정보를 담당한다.
4. init 메서드 오버라이드
@Override
public void init() throws ServletException {
rehm = new RequestMappingHandlerMaping();
rehm.init();
}
init 메서드를 오버라이드하여 서블릿 초기화시에 RequestMappingHandlerMaping 객체를 생성하고 초기화한다.
5. service 메서드 오버라이드
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("[DispatcherServlet] service started");
try {
Controller handler = rehm.findHandler(request.getRequestURI());
String viewName = handler.handleRequest(request, response);
RequestDispatcher requestDispatcher = request.getRequestDispatcher(viewName);
requestDispatcher.forward(request, response);
} catch (Exception e) {
log.error("exception occured: [{}]", e.getMessage(),e);
throw new ServletException(e);
}
service 메서드를 오버라이드하여 클라이언트의 요청이 들어올 때마다 호출되는 부분이다 다음과 같은 동작을 수행한다.
RequestMappingHandlerMaping 을 통해 요청 URL에 해당하는 Controller를 찾는다.
해당 Controller 를 사용하여 요청을 처리하고 반환된 뷰 이름을 얻는다.
RequestDispatcher 를 사용하여 뷰로 forward 한다.
예외가 발생하면 로그를 남기고 ServletException을 던진다.
위 코드들은 MVC 패턴을 기반으로 하는 웹 애플리케이션에서 클라이언트의 요청을 받아 적절한 컨트롤러로 전달하고 컨트롤러가 처리한 결과를 다시 뷰로 전달하여 화면에 표시하는 역활을 하는 서블릿이다.
package org.example.mvc.controller;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Controller {
String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
이 코드는 MVC 아키텍처에서 컨트롤러 역활을 하는 인터페이스를 정의한 것이다 컨트롤러는 클라이언트 요청을 처리하고 그 결과로 뷰의 이름을 반환하는 역활을 한다.
public interface Controller {
String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Controller 인터페이스는 하나의 메서드를 선언하고 있다
String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exeption; 이메서드는 클라이언트 요청을 처리하는데 사용된다 HttpServletRequest 는 클라이언트의 HTTP 요청을 나타내며 HttpServletResponse 는 서버에서 클라이언트의 HTTP 응답을 나타낸다. 메서드는 예외를 던질 수 있으며 구체적인 구현에서는 요청을 처리하고 뷰의 이름을 반환하는 등의 작업을 수행할 것이다.
** Controller 인터페이스 활용:
public class SomeController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 컨트롤러의 구체적인 로직을 구현
// ...
return "viewName"; // 뷰의 이름을 반환
}
}
Controller 인터페이스를 구현한 구체적인 컨트롤러 예시이다.
HandleRequest 메서드에서는 실제로 클라이언트의 요청을 처리하고 뷰의 이름을 반환한다.
이 인터페이스를 사용하면 여러 컨트롤러 클래스를 정의하고 각각의 컨트롤러가 특정 유형의 요청을 처리하도록 할 수 있다 이것은 MVC 패턴에서 모델,뷰,컨트롤러를 분리하여 유지보수성과 확장성을 높이는 데 기여한다.
package org.example.mvc.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HomeController implements Controller{
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return "home.jsp";
}
}
return "home.jsp";
메서드에서는 단순히 문자열 "home.jsp" 를 반환 하고있다 이것은 클라이언트에게 표시할 뷰 페이지의 이름을 나타낸다.
package org.example.mvc;
import org.example.mvc.controller.Controller;
import org.example.mvc.controller.HomeController;
import java.util.HashMap;
import java.util.Map;
public class RequestMappingHandlerMaping {
// [key] /users [value] UserController
private Map<String, Controller> mappings = new HashMap<>();
void init() {
mappings.put("/", new HomeController());
}
public Controller findHandler(String urlPath) {
return mappings.get(urlPath);
}
}
이 코드는 URL 경로와 그에 대응하는 컨트롤러를 매핑하고, 클라이언트의 요청에 따라 적절한 컨트롤러를 찾아 반환하는
RequestMappingHandlerMaping 클래스이다.
private Map<String, Controller> mappings = new HashMap<>();
mapppints 는 URL 경로를 키로 해당 URL에 대응하는 컨트롤러 값으로 가지는 HashMap 이다.
void init() {
mappings.put("/", new HomeController());
}
init 메서드에서는 초기에 매핑 정보를 설정합니다. 예시로 "/" 경로에 대응하는 HomeController 객체를 매핑했습니다.
public Controller findHandler(String urlPath) {
return mappings.get(urlPath);
}
findHandler 메서드는 매핑 정보를 통해 클라이언트의 요청에 대응하는 컨트롤러를 찾아 반환합니다. URL 경로(urlPath)를 인자로 받아 해당 경로에 대응하는 컨트롤러를 mappings에서 찾아 반환합니다.
'JAVA > MVC 프레임워크' 카테고리의 다른 글
DI 프레임워크 (1) | 2023.11.24 |
---|---|
프런트 컨트롤러 패턴 개념 (0) | 2023.11.09 |
리플렉션 API 개념 (0) | 2023.11.08 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!