우와한 개발자

[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);
            }
        }
    }
}

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기