아... 글쓰다가 날려먹었네요...으..아...어..아.........(멘붕)

세상에 거의다 써가고 있었는데.. 

처음부터 다시ㅠㅠ


저번시간에는 View의 코드 분리를 하였고 이제부터 MVC패턴의 C인 컨트롤러를 구성해보겠습니다.

컨트롤러에서는 Java파일 즉, 클래스 파일로 넘어가기때문에 html, javascript코드는 볼 수 없습니다.

MVC가 어떻게 거쳐 동작하는지 간단하게 알아봅시다.

http://cusmaker.tistory.com/86


사용자 Browser에서 요청이 날라옵니다. 요청은 write.jsp처럼 페이지를 요청하는 건데 MVC에서는 요청이 바로 jsp로

바로 넘어가는게 아니라 Action(클래스명)을 거치게 됩니다. 이 자바 파일에서 비즈니스로직(로그인, 데이터가져오기, 세션, 유효성검증 등등)을 수행하고 View(.jsp)에서 필요한 데이터만 페이지로 넘기게 되겠습니다.

그렇기때문에 .jsp로 요청하는게 아닌 .do or .action등 다른 방식으로 URL을 요청하게됩니다. 인터넷 서핑하다보면

.jsp가 아닌 .do나 다른 확장자로 요청하는 것을 간간히 볼 수 있습니다. 이렇게 날아온 요청은 

해당 Action에 맵핑시키기위해 해당 맵핑정보가 있는 Properties파일(보통 텍스트파일)을 읽고 해당 클래스에 접근할 수 있게

해준다음 실행하게 되겠습니다. 

해당 Action에서 데이터베이스에 접속이 필요하다고 하면 이때 Model이 사용되게 됩니다.

Model은 DB의 접속(트랜잭션관리, 커넥션 풀 관리 등)과 각종 쿼리들을 처리할 수 있게 메소드 빈 형식으로 구성됩니다.

데이터베이스에 접근한 뒤 필요한 데이터를 반환하거나 수정, 삭제하고 다시 Action으로 돌아와 View에서 필요한 데이터를

jsp페이지로 보내면서 반환합니다 (dispatcher합니다)

로그인을 예로 들어보겠습니다.

사용자가 browser에서 id와 pw값을 가진 login.do를 요청 -> Controller에서 login.do의 기능을 하는 Action을 매칭 ->

해당 Action에서 사용자가 보낸 값인 id와 pw를 가지고 Model에 쿼리를 실행 -> 해당 Action에서 로그인 처리 ->

값에 따른 로그인 성공, 실패 페이지(JSP)로 반환

전체적인 흐름은 위와 같습니다.


자 그러면 먼저 사용자가 *.do로 요청할 때 처리할 수 있도록 기능을 만들어야겠죠?

먼저 index.jsp를 list.do로 바꾸어줍시다. 파일은 list.jsp로 고쳐주시고 링크같은 경우는 list.do로 바꾸어 줍시다.

<script>location.href="list.do";</script>


사용자가 *.do로 접속했을 때 제일 먼저 처리할 수 있도록 해야합니다. 그러기 위해선 WebContent->lib->web.xml파일을

고쳐주어야합니다.

없는 경우도 있는데 그럴때 우클릭 -> Other -> xmlfile로 만들어주시면 됩니다.

  <servlet>

   <servlet-name>ControllerAction</servlet-name>

   <servlet-class>com.board.controller.ControllerAction</servlet-class>

</servlet>

 

<servlet-mapping>

   <servlet-name>ControllerAction</servlet-name>

   <url-pattern>*.do</url-pattern>

</servlet-mapping>


위의 구문을 web.xml에 추가하시면됩니다. </welcom-file-list>아래 </web-app>위에


간단하게 설명해보자면 

<servlet>태그안에 name은 컨트롤러 이름을 설정하는것이고 class는 컨트롤러가 있는 위치를 지정해줍니다.

<servlet-mapping>태그안에 name은 맵핑할 컨트롤러 이름을 가져오는 것이고, url-pattern은 어떤 url로 들어오면

컨트롤러로 보낼것인지 설정하는 겁니다. 결과적으로 *.do로 오는 요청은 ControllerAction을 거치게 되는 것이죠.

자 그러면 우리는 web.xml에 ControllerAction을 선언했습니다만, 소스에는 저 ControllerAction이 없습니다.

그럼 만들어주어야죠. 


이제 ControllerAction에 내용을 넣어봅시다.

package com.board.control;
 
import java.io.*; 
import java.util.*; 
import javax.servlet.*; 
import javax.servlet.http.*;
 
public class ControllerAction extends HttpServlet {
 
    private Map commandMap = new HashMap(); // 명령어와 명령어 처리 클래스를 쌍으로 저장
 
    public void init(ServletConfig config) throws ServletException {
 
        // Common properties 
        loadProperties("com/board/properties/Command");
 
    }
 
    // properties 설정 
    private void loadProperties(String path) {
 
        ResourceBundle rbHome = ResourceBundle.getBundle(path);// 누구를 실행할지를 rb에
                                                                // 저장.
 
        Enumeration<String> actionEnumHome = rbHome.getKeys();
 
        while (actionEnumHome.hasMoreElements())
 
        {
 
            String command = actionEnumHome.nextElement();
           
 
            String className = rbHome.getString(command);
 
            try {
 
                Class commandClass = Class.forName(className); // 해당 문자열을 클래스로
                                                                // 만든다
 
                Object commandInstance = commandClass.newInstance(); // 해당 클래스의
                                                                        // 객체를
                                                                        // 생성
 
                commandMap.put(command, commandInstance); // Map 객체인 commandMap에
                                                            // 객체 저장
 
            } catch (ClassNotFoundException e) {
 
                continue; // error
 
                // throw new ServletException(e);
 
            } catch (InstantiationException e) {
 
                e.printStackTrace();
 
            } catch (IllegalAccessException e) {
 
                e.printStackTrace();
 
            }
 
        }
 
    }
 
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        requestPro(request, response); // get방식과 post방식을 모두 requestPro로 처리
 
    }
 
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
 
        requestPro(request, response);
 
    }
 
    // 사용자의 요청을 분석해서 해당 작업을 처리
 
    private void requestPro(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
 
        String view = null;
 
        CommandAction com = null;
 
        try {
 
            String command = request.getRequestURI();
 
            if (command.indexOf(request.getContextPath()) == 0) {
 
                command = command.substring(request.getContextPath().length());
 
            }
 
            com = (CommandAction) commandMap.get(command);
 
            if (com == null) {
 
                System.out.println("not found : " + command);
 
                return;
 
            }
 
            view = com.requestPro(request, response);
 
            if (view == null) {
 
                return;
 
            }
 
        } catch (Throwable e) {
 
            throw new ServletException(e);
 
        }
 
        if (view == null)
 
            return;
 
        RequestDispatcher dispatcher = request.getRequestDispatcher(view);
 
        dispatcher.forward(request, response);
 
    }
 
}

위의 소스코드로 입력하시면 빨간 줄이 많이 뜨는 것을 확인할 수 있습니다. 

같은 경로에서 CommandAction이라는 클래스를 하나더 만들어 줍시다. 그리고 다음 소스코드를 입력합시다.


package com.board.control;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public interface CommandAction {

public String requestPro(HttpServletRequest request, HttpServletResponse response) 

throws Throwable;

}

CommandAction은 명령어에서 찾은 클래스를 클래스화 시키는 것입니다. 

※ 추가적인 공부가 필요할 듯싶네요..


다시 ControllerAction으로 돌아와서 소스코드를 보시면 

init에서 com/board/properties/Command에서 맵핑정보를 가진 Properties파일을 로드해옵니다.

그렇다면 com/board/properties/Command에 Properties파일을 만들어주어야겠죠. 마저 설명하고 만들러 가봅시다.

로드해와서 loadProperties에서 맵핑을하면서 패키지 정보를 바탕으로 클래스화 시킨뒤 리소스 번들이라는 객체에

저장하게 됩니다. 

이제 Properties를 만들러갑시다. 

src에서 com.board.proerties라는 패키지를 만들어주고 new -> file -> Command.properties로 파일을 생성합니다.

우측에는 Command.properties 파일의 내용인데요. /list.do로 들어오는 요청은 com.board.action.ListAction으로 처리하겠다는 겁니다.

다음에 뭐 만들어야 될지 감이 오겠죠?

com.board.action이라는 패키지를 만들고 ListAction이라는 클래스를 만들어 줍시다.

만약 다른 Action이 추가될때마다 여기 경로에 추가해줘야 매칭이 되겠습니다.


다시 ControllerAction으로 돌아와서 

post요청과 get요청이 들어오면 requestPro라는 함수를 호출하여 처리합니다. 

requestPro함수에서는 사용자의 요청 URL을 분석하여 리소스 번들에 저장된 해당 액션 객체를 실행합니다.

해당 액션 객체의 실행이 끝나면 액션에서 리턴되는 뷰(파일경로, 이름)로 리턴합니다. 


ControllerAction은 끝났고 아까전에 만들어두었던 ListAction을 마저 완성하러 갑시다.

내용을 넣기전에 먼저 Command Action 인터페이스를 적용시켜 봅시다

Line 3 
public  class ListAction {

}

public class ListAction implements CommandAction{

}

으로 바꿔줍시다. 

그러면 라인앞에 전구표시가 뜨는데 Add unimplemented methods를 클릭하면 소스가 생깁니다.

이제 내용을 채워야하는데 이미 ListAction에서 동작할 소스는 만들어져 있습니다.

어딨냐면 list.jsp에 스크립트릿으로 존재합니다. 

list.jsp에 있는 스크립트릿을 복사하여 ListAction에 붙여넣기 합시다.

스크립트릿 처리는 ListAction에서 하기때문에 list.jsp에서는 더이상 스크립트릿이 필요하지 않습니다.

당연히 지워주어야합니다.

그리고 ListAction으로 온 소스에 out.print ~의 앞에 System.을 붙여줍시다. ( 콘솔창에 메시지가 떠요)

컨트롤러의 구성과 ListAction의 작업이 끝났습니다.

직접 손으로 다 쳐보시길 바랍니다.(오타를 잡으면서.......)

정상적으로 실행이 된다면 아래와 같이 나올겁니다.

URL을 보면 list.do로 요청이 가는 것을 볼 수 있습니다. list.jsp하면 아무것도 안떠요.

list.do로 흐름도를 보자면

사용자가 list.do 요청 -> web.xml에서 url을 파악하여 ControllerAction으로 전달 -> ControllerAction에서 Command.properties를 통해 맵핑, 요청 분석 -> ListAction으로 맵핑이 되고, 실행 -> view에 필요한 데이터를 .jsp로 리턴


이 포스팅에서는 ListAction만 구현되어 있습니다. Write, Delete, Modify등등 직접 구현해보시길 바랍니다.

여기까지가 MVC에서 C(컨트롤러)를 만들었습니다. 하지만 아직 ListAction에 데이터베이스 접속하는 로직이 포함되어있습니다.

데이터베이스 접속하는 로직은 Model으로 분리를 해주어야 MVC가 완성이 되겠습니다. 


+ Recent posts