Spring 예제#2 ( Adapter Handler, FrontController )

2024. 8. 29. 16:15JAVA 기반 웹개발/SERVLET & JSP

Adapter handler

Adapter Handler 사용이유

  • 한가지 로직을 실행시키는데에 있어, A/B 경우를 골라야한다면 어떻게 처리해야할지에 대한 의문
    • frontcontroller 의 경우 한가지 방식의 컨트롤러 인터페이스만 사용 가능

 

Adapter Handler 도식화

 

 

수정해야하는 부분

  • FrontController class에서 Controller를 객체 그대로 받는 경우가 수정되어야한다
(Before)
private Map<String, Controller> controllerV3Map = new HashMap<>();

(After)
MyHandlerAdapter adapter = getHandlerAdapter(handler);
ModelView mv = adapter.handle(request, response, handler);

 

 

Adapter Interface 생성

  • handler == controller
  • adapter는 실제 controller 호출 후 ModelView 반환
public interface MyHandlerAdapter{
     
     boolean supports(Object handler);
     
     ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws ServletException,IOException;
     }
     
}

 

Adapter 생성

  • 각각의 인터페이스의 맞는 어뎁터 생성
  • Controller , Controller2
public class ControllerHandlerAdapter implements MyHandlerAdapter{

    @Override
    public boolean supports(Object handler){
        return (handler instanceOf Controller);
    }
    
    
    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    {
         // 해당 컨트롤러 인터페이스로 캐스팅
         Controller controller = (Controller) handler;
         
         // 이후 작업은 동일
         Map<String, String> paramMap = createParamMap(request);
         
         ModelView mv = controller.process(paramMap);
         return mv;
    }
    
    private Map<String, String> createParamMap(HttpServletRequest request){
         Map<String,String> paramMap = new HashMap<>();
         
         request.getParameterNames().asIterator()
           .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
         
         return paramMap;
    }    
   
}


public class Controller2HandlerAdapter implements MyHandlerAdapter{
    
    @Override
    public boolean supports(Object handler)
    {
        return (handler instnaceOf Controller2);
    }
    
    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler){
        
        Controller2 controller = (Controller2) handler;
        
        // 이후 작업은 동일
         Map<String, String> paramMap = createParamMap(request);
         
         ModelView mv = controller.process(paramMap);
         return mv;
    }
    
    private Map<String, String> createParamMap(HttpServletRequest request){
         Map<String,String> paramMap = new HashMap<>();
         
         request.getParameterNames().asIterator()
           .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
         
         return paramMap;
        
     }
}

 

FrontController 수정

  • Controller 와 Controller2의 map을 준비
  • adapter를 이용한 handler(==controller) 호출
//adapter 하위로 들어오는 경우 모두 타겟팅
@WebServlet(urlPatterns="/main/adapter/*")
public class FrontController extends HttpServlet{
    
    private final Map<String, Object> handlerMappintMap = new HashMap<>();
    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();
    
    public FrontController(){
       initHandlerMappingMap();
       initHandlerAdpaters();
    }
    
    private void initHandlerMappingMap(){
        handlerMappingMap.put("/main/adapter/controller/new-form", new MemberFormController());
        handlerMappingMap.put("/main/adapter/controller/save", new MemberSaveController());
        handlerMappingMap.put("/main/adapter/controller/members", new MemberListController());
        
        handlerMappingMap.put("/main/adapter/controller2/new-form", new MemberFormController2());
        handlerMappingMap.put("/main/adapter/controller2/save", new MemberSaveController2());
        handlerMappingMap.put("/main/adapter/controller2/members", new MemberListController2());
    }
    
    private initHandlerAdapters(){
        handlerAdapters.add(new ControllerHandlerAdapter());
        handlerAdapters.add(new Controller2HandlerAdapter());
    }
    
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletExcetption, IOException{
        
        Object handler = getHandler(request);
        
        if(handler == null){
             response.setStatus(HttpServletResponse.SC_NOT_FOUND);
             return;
        }
        
        MyHandlerAdapter adapter = getHandlerAdapter(handler);
        
        ModelView mv = adapter.handle(request, response, handler);
        
        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        
        view.render(mv.getModel(), request, response);
        
     }
     
     private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if(adapter.supports(handler)){
                return adapter;
            }
        }
        throw new IllegalArgumentException("Handler adapter를 찾을 수 없습니다. handler " + handler);
    }

    private Object getHandler(HttpServletRequest req) {
        String requestURI = req.getRequestURI();
        Object handler = handlerMappingMap.get(requestURI);

        return handler;
    }

    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
 
 }

 

정리

  • Controller1 과 Controller2의 경우, 같은 로직의 이름만 다르게해서 Adapter를 적용해보았다
  • 하지만, 인터페이스 구조가 다를경우 ControllerHandlerAdapter가 서로 다른 구조였을 것이다 ( handle() 부분 )
  • 이렇듯, adapter를 사용하면 "변압기"처럼 원하는 것을 끼우며 사용할 수있다
  • 더 나아가, Annotaion을 지원하게 된다면 스프링과 유사하게 프레임워크를 구성할 수 있게 된다.

'JAVA 기반 웹개발 > SERVLET & JSP' 카테고리의 다른 글

Spring 예제#1 ( +Servlet, JSP, FrontController )  (0) 2024.08.29
MVC 패턴 ( Servlet + JSP )  (1) 2024.08.28
순수 JSP 예제  (1) 2024.08.28
JSP 이론 및 기초 문법  (1) 2024.08.28