[Spring] Servlet 요청 처리 - 커맨드 패턴(Command Pattern)과 Handler 분기(properties 설정파일)
by 우와한개발자
1. 커맨드 패턴 (Command Pattern)
- 요청을 객체로 캡슐화하여, 요청을 보내는 객체와 처리하는 객체를 분리하는 행동 디자인 패턴.
- HttpServletRequest 객체에는 HTTP 요청의 header, body, parameter 등 정보가 담겨 있음
- doGet()과 doPost()를 하나의 processRequest() 메서드로 합쳐서 처리하는 방식을 주로 사용
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
processRequest(req, res);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
processRequest(req, res);
}
private void processRequest(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 분기 처리 로직
}
}
2 커맨드 분기 처리 방법
| 구분 | if-else | 설정파일(.properties)과 Map |
| 설정 위치 | Servlet 코드 | 외부 파일 분리 |
| 기능 추가 시 | Servlet 수정 필요 | properties만 추가 |
| 복잡도 | 낮음 | 높음 |
1) if-else 분기 처리 방식
- URL 파라미터(예: ?action=join)로 어떤 기능을 수행할지 결정
private void processRequest(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
String action = req.getParameter("action");
if ("join".equals(action)) {
// 회원가입 처리
} else if ("login".equals(action)) {
// 로그인 처리
} else if ("update".equals(action)) {
// 정보 수정 처리
}
// 기능이 늘어날수록 else if 계속 추가해야 함
}
2) 설정파일(.properties)과 Map을 이용한 분기처리 방식
- Handler 인터페이스를 정의하고, 클래스명을 외부 파일에 문자열로 관리
- Class.forName()으로 문자열을 설계도(Class 객체)로 변환하고, 요청이 올 때 newInstance()로 객체 생성
(1) Handler 인터페이스와 구현 클래스
// 1. Handler 인터페이스 정의
public interface Handler {
void execute(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException;
}
// 2. 각 기능을 Handler로 구현
public class JoinHandler implements Handler {
@Override
public void execute(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 회원가입 처리 로직
}
}
(2)handler.properties
- action과 클래스명 매핑을 외부 파일로 분리
- 값 끝에 공백이 들어가면 Class.forName() 실패 → 주의
join=com.example.handler.JoinHandler
login=com.example.handler.LoginHandler
update=com.example.handler.UpdateHandler
(3) Servlet
| 코드 | 설명 |
| Class.forName(className) | 문자열 클래스명 → Class 객체(설계도)로 변환 |
| clazz.getDeclaredConstructor().newInstance() | 설계도로 실제 객체 생성 |
| getResourceAsStream("handler.properties") | classpath에서 properties 파일을 읽어옴 |
| props.load(is) | 스트림을 key=value 형태로 파싱 |
@WebServlet("/member")
public class MemberServlet extends HttpServlet {
private Map<String, Class<? extends Handler>> handlerMap = new HashMap<>();
@Override
public void init() throws ServletException {
try {
// 1. .properties 파일 로드
Properties props = new Properties();
InputStream is = getClass().getClassLoader()
.getResourceAsStream("handler.properties");
props.load(is);
// 2. 문자열 클래스명 → Class 객체(설계도)로 변환해서 Map에 등록
for (String action : props.stringPropertyNames()) {
String className = props.getProperty(action);
Class<? extends Handler> clazz =
(Class<? extends Handler>) Class.forName(className);
handlerMap.put(action, clazz);
}
} catch (Exception e) {
throw new ServletException("Handler 초기화 실패", e);
}
}
private void processRequest(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
String action = req.getParameter("action");
Class<? extends Handler> clazz = handlerMap.get(action); // 설계도 꺼내기
if (clazz != null) {
try {
Handler handler = clazz.getDeclaredConstructor().newInstance(); // 요청 시 객체 생성
handler.execute(req, res);
} catch (Exception e) {
throw new ServletException(e);
}
}
}
}
'프레임워크 > Spring' 카테고리의 다른 글
블로그의 정보
우와한개발자 님의 블로그
우와한개발자