1. JSP DP의 Front Controller Partten(Figure 7-2,p145)에 대응되는 Struts의 그림은?

사용자 삽입 이미지

JSP DP에 나오는 front controller pattern











front controller pattern은 사용자의 요청을 하나의 controller가 받아서 helper로 감싼다. 그리고 helper를 통해 각 요청에 맞는 command를 생성한 후, 그렇게 생성된 command가 요청을 처리하도록 위임한다.


사용자 삽입 이미지

Struts MVC Architecture

지금 이 그림은 front controller pattern 관점에서 본 Struts이다.
역시 사용자의 요청을 하나의 servlet이 받아서 적절한 action을 생성하고, 처리를 위임한다.



사용자 삽입 이미지

Struts in front controller pattern











Struts를 JSP DP의 front controller pattern과 비교해보면 위 그림처럼 연결할 수 있다.
하나의 ActionServlet이 모든 요청을 받고, RequestProcessor를 호출한다.
RequestProcessor는 struts-config.xml을 참조해서 해당 요청에 적합한 Action을 생성하고,
Action을 실행시킨다. 이 Action은 비즈니스 로직을 수행하고, 결과에 따라 struts-config.xml을 참조해서 AcitionMapping을 통해 View(JSP)를 지정하고, 결과를 뿌려준다.

참고 : ¹Struts Sequence Diagram (출처)
         ²Struts Flow Diagram (출처)

2. Struts의 front controller pattern은 어떻게 구현되어 있나?

사용자 삽입 이미지

Struts Class Diagram


Class ActionServlet
ActionServlet은 단지 Request를 가로채는 역할만 할 뿐, 실질적인 모든 작업은 RequestProcessor가 담당한다. ActionServlet의 doGet과 doPost에서는 단지 process()에 작업을 위임한다.

public
void doGet(HttpServletRequest request,
              HttpServletResponse response)
        throws IOException, ServletException {
        process(request, response);
    }
public void doPost(HttpServletRequest request,
              HttpServletResponse response)
        throws IOException, ServletException {
        process(request, response);
    }

protected
void process(HttpServletRequest request,
                           HttpServletResponse response)
        throws IOException, ServletException {

        RequestUtils.selectModule(request, getServletContext());
        // → Create request helper object 에 해당.
        getRequestProcessor(getModuleConfig(request)).process
         (request, response);
    }
--------------------------------------------------------------------------
Class RequestProcessor
ActionServlet에서 중간에 가로챈 Request에 대한 모든 작업을 전담.

public
void process(HttpServletRequest request,
                        HttpServletResponse response)
        throws IOException, ServletException {

        // Wrap multipart requests with a special wrapper
        request = processMultipart(request);

        // Identify the path component we will use to select a mapping
        // Request의 URI로부터 Path를 추출하여 반환한다.
        String path = processPath(request, response);
        if (path == null)
        {  return; }
        if (log.isInfoEnabled()) {
            log.info("Processing a '" + request.getMethod() + "' for path '" + path + "'");
        }

        // Select a Locale for the current user if requested
        processLocale(request, response);

        // Set the content type and no-caching headers if requested
        processContent(request, response);
        processNoCache(request, response);

        // General purpose preprocessing hook
        /* Servlet Filter와 같은 역할을 한다. Request가 처리되기 전에 처리해야 할 작업 처리.
            RequestProcessor를 상속하는 새로운 클래스를 만들어 processPreprocess()를
           오버라이드, 만약 모든 request가 사용자가 로그인한 상태여야 한다면, 여기서 확인
 
        */
        if (!processPreprocess(request, response)) {
            return;
        }

        // Identify the mapping for this request
        /* 요청한 request에서 사용할 ActionMapping객체를 생성하는 과정
            Path정보에 해당하는 Mapping정보가 없으면 에러가 포함되 response가 반환.
        */

        ActionMapping mapping = processMapping(request, response, path);
        if (mapping == null) {
            return;
        }

        // Check for any role required to perform this action
        if (!processRoles(request, response, mapping)) {
            return;
        }

        // Process any ActionForm bean related to this request
        // ActionMapping에 ActionForm이 설정되어 있다면 ActionForm 인스턴스를 생성.
        ActionForm form = processActionForm(request, response, mapping);

        // request에서 전달되는 인자를 앞에서 생성된 ActionForm 인스턴스에 저장.
        processPopulate(request, response, form, mapping);
        if (!processValidate(request, response, form, mapping)) {
            return;
        }

        // Process a forward or include specified by this mapping
        if (!processForward(request, response, mapping)) {
            return;
        }
        if (!processInclude(request, response, mapping)) {
            return;
        }

        // Create or acquire the Action instance to process this request
        // request에 해당하는 Action 인스턴스를 생성. 기 존재하면 재사용하게 함.
        // → Create action object (command) 에 해당.
        Action action = processActionCreate(request, response, mapping);
        if (action == null)
        {       return;     }

        // Call the Action instance itself
        // 앞서 생성한 Action instance의 execute()메써드를 호출, Action인스턴스를 실행시킴.
        // → Execute action 에 해당.
        ActionForward forward =
            processActionPerform(request, response, action, form, mapping);

        // Process the returned ActionForward instance
        // Action instance의 execute()를 실행한 결과 반환된 ActionForward에 해당하는 URL로
        // forward시키는 과정.
        // → Dispatch to appropriate view 에 해당.
        processActionForward(request, response, forward);
    }


참고 :
Jakarta Struts 강좌 4 - 스트러츠의 핵심 클래스들


--------------------------------------------------------------------
JSP DP source
public class Controller extends HttpServlet {
  public void init()
  { /* Perform first-time initialization of shared resources such as DB connections */  }

  public void doGet(HttpServletRequest _req, HttpServletResponse _res)
    throws ServletException, IOException
  {
    /* Forward to doPost method */
    doPost(_req, _res);
  }

  public void doPost(HttpServletRequest _req, HttpServletResponse _res)
    throws ServletException, IOException
  {
    /* Create request helper object */
    ReqUtility reqUtil = new ReqUtility(_req);

    /* Create action object (command) */
    Action action = reqUtil.getAction();

    /* Execute action */
    String view = action.execute(_req, _res);

      /*  Dispatch to appropriate view */
      RequestDispatcher dispatcher = _req.getRequestDispatcher(view);
      dispatcher.forward(_req, _res);
    }
  }

  public void destroy()
  { /* Perform cleanup opeations here like closing DB */ }
}

--------------------------------------------------------------------------------
public class ReqUtility {
  HttpServletRequest request;
  public ReqUtility(HttpServletRequest _req)
    throws ServletException, IOException
  {
    request = _req;
  }
  public Action getAction()
  {
    /* Use factory to create action based on request parms */
    String action = (String) request.getParameter("action");
    return ActionFactory.createAction(action);
  }
}


기타 :
Javajigi Model1, Model2, Struts 개발 방식의 비교 분석
Jakarta Struts 강좌 1
Forward할 정보들을 Action을 상속하여 구현하는 클래스의 소스코드에 직접 입력하였다. 이 같이 할 경우 Forward URL이 바뀌거나 할 경우 소스코드를 수정후 새로 컴파일해야하는 불편함이 있다. 따라서 스트러츠에서는 모든 정보들을 struts-config.xml에 저장하여 관리하도록 하였다. Application이 시작할 때 struts-config.xml의 모든 정보를 읽어 관리하는 역할을 담당하는 클래스가 ActionMapping클래스이다. ActionMapping클래스처럼 Application의 Action클래스, Forward URL, Exception등의 정보를 관리하는 클래스가 존재하기 때문에 여러개의 Servlet이 없이 하나의 ActionServlet만 있어도 되는 것이다.

사용자가 입력하거나 페이지에 의하여 전달되는 모든 정보는 Request객체에 저장되어 넘어온다. 이 같이 Request에 저장되어 있는 정보들을 자바빈 클래스에 저장하여 개발자가 추출하기 편하도록 지원하는 클래스가 ActionForm클래스이다.

Application을 개발하다 보면 무수히 많은 에러가 발생한다. 이 같이 Application에서 발생하는 에러를 저장하여 사용자에게 전달하는 역할을 하는 클래스의 중심에 ActionErrors클래스가 있다.

1. 그림설명
7.1 Struts개요
7.2 Struts 사용하기
Struts 의 효율성?
"수백개의 페이지들에 대한 플로우를 그런식으로 꼭 설정파일에 담아놔야하느냐?
그 작업이 과연 개발은 둘째치고, 유지보수에라도 도움이 되느냐? " 등등....
MS 개발자들은 자바개발자들에 비해서 굉장히 현실적이거든요...(물론 제 느낌입니다.)
http://conferences.codegear.com/kr/article/32246
http://www.agiledeveloper.com/articles/JSPMVC.pdf
¹How Struts Works : Struts flow에 대해 설명
²http://www.oracle.com/technology/global/kr/pub/columns/millsonMVC.html
Comparing Web Frameworks
https://equinox.dev.java.net/framework-comparison/WebFrameworks.pdf

http://java.sun.com/blueprints/patterns/
http://www.zdnet.co.kr/builder/dev/etc/0,39031619,39131310,00.htm
9페이지 Struts Flow Diagram
http://www.scakorea.org/data/sca_framework.pdf

Posted by 라딘.

댓글을 달아 주세요