ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WEB:Model2] 컨트롤러 만들기
    비전공자 공부일기/:: WEB & Front-End 2019. 8. 12. 19:32

    2019. 08. 12 필기

     

     

     

    컨트롤러(Controller)란?

    : MVC 중의 Controller는 클라이언트(브라우저)의 모든 요청을 받아 필요한 모델(Model)을 이용하여 요청처리 후 처리 결과를 뷰(View)로 전달하는 기능의 서블릿이다.

     

     

     

    Model2에서 사용되는 컨트롤러는 서블릿으로 만들어진다.

     

     

    컨트롤러의 역할

     

    1. 웹브라우저가 전송한 HTTP 요청을 받는다. doGet() doPost() 메소드 이용

    2. 브라우저의 요청을 분석한다.

    3. 모델을 사용하여 요청한 기능을 수행한다.

    4. 웹브라우저에 보여줄 

     

     

     

     

    1. 클라이언트의 모든 요청을 받을 수 있는 단일 진입점 기능 구현

      >> web.xml 파일 환경설정

     

    클래스를 서블릿으로 등록하는 방법에는 두 가지가 있다.

    바로 클래스 위에 @WebServlet 어노테이션을 선언해주는 방법 또는 web.xml에 등록해주는 방법인데, 일반적으로 어노테이션을 이용하는 것이 더 편리하지만 유지보수의 측면에서는 web.xml이 낫다. 또한 서블릿이 하나만 있을 때는 web.xml 파일을, 다수라면 @어노테이션을 사용하는 것이 좋다.

     

     

    1) web.xml 이용하는 방법

     

    프로젝트 > WebContent > WEB-INF > web.xml  의 내용에 서블릿을 등록해주는 방식이다.

     

    web.xml 파일로 서블릿을 설정한다면 서블릿 등록과 URL 매핑을 해주어야 한다. **HelloServlet 참조

    => 소스파일 변경 없이 다양한 환경설정

     

    ** 주의! web.xml 문서는 한 번 저장할 때 시간이 오래 걸리기 때문에 습관적으로 ctrl+s를 누르는 (나같은) 사람은 주의해야 한다!

     

    ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * 
    
    <servlet>
      <servlet-name>서블릿이름</servlet-name>
      <servlet-class>등록하려는 클래스의 주소</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>서블릿이름</servlet-name>
      <url-pattern>사용하려는 URL 패턴</url-pattern>
    </servlet-mapping>
    
    ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * ~ * 
    
    
    위와 같은 형식을 사용하면 되는데, 아래는 예시이다.
      
    
    
    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
      <display-name>mvc</display-name>
      <servlet>
        <servlet-name>controller</servlet-name>
        <servlet-class>site.itwill.model.ControllerServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>controller</servlet-name>
        <url-pattern>*.do</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
        <welcome-file>index.do</welcome-file>
      </welcome-file-list>
    </web-app>

     

     

     

    2) @어노테이션 이용하는 방법

     

    @WebServlet(String url) : 서블릿 등록과 URL 매핑 기능의 어노테이션 
     =>  *는 전체, ?는 한 문자를 뜻함 

     

    @WebServlet(name="controller.itwill") >> 이런 형식은 단일진입점 역할을 할 수 없음 

    --- name 속성은 필수가 아님 

     

    괄호 ( ) 안에는 URL 주소 대신 패턴(wild character : * 또는 ?)을 이용하여 설정할 수도 있다.


    @WebServlet("?.do")  --- WebServlet(name) 어노테이션으로 클래스 자체를 서블릿으로 등록

     

    위와같이 지정해주면 이제 해당 서블릿은 클라이언트에서 "~.do" 형식의 URL 주소로 요청한 경우 실행되는 서블릿된 것이라고 보면 된다.

     

     

    여러 웹사이트들을 둘러볼 때 URL 뒤에 일정한 키워드가 붙는 것을 볼 수 있다.

     

    예를 들어 www.dummyurl.com/index.do >> www.dummyurl.com/sales.do 

    --- 위처럼 페이지를 이동했을 때 각기 url 뒤에 do라는 단어가 동일하게 붙어있는 것을 볼 수 있다.

    --- do는 흔히 이용되는 키워드 중의 하나인데, 큰 의미는 없고 '하다'라는 뜻 정도임


    이 키워드는 개발자가 마음대로 지정할 수 있으나, 보통 사이트에 따라 도메인 키워드로 지정하거나 좀 큰 포털사이트의 경우 카테고리별로 지정하는 것도 볼 수 있다.



     

     

     

     2. 클라이언트의 요청 분석

     

    클라이언트의 요청을 분석하고, 그 내용을 매개변수에 저장

     

    HttpServletRequest.getRequestURI( ) : 요청 URL 주소의 URI 값을 반환  => /mvc/XXX.do

    HttpServletRequest.getContextPath( ) : 요청 URL 주소의 컨텍스트 경로 반환 => /mvc

    URI 값에서 컨텍스트 경로를 제외한 문자열을 분리하여 저장 => /XXX.do

     

     

    //HttpServletRequest.getRequestURI() : 요청 URL 주소의 URI 값을 반환하는 메소드 => /mvc/XXX.do
    String requestURI=request.getRequestURI();
    //System.out.println("requestURI = "+requestURI);
    
    //HttpServletRequest.getContextPath() : 요청 URL 주소의 컨텍스트 경로를 반환하는 메소드 => /mvc
    String contentPath=request.getContextPath();
    //System.out.println("contentPath = "+contentPath);
    
    //URI 값에서 컨텍스트 경로를 제외한 문자열을 분리하여 저장 => /XXX.do
    String command=requestURI.substring(contentPath.length());
    //System.out.println("command = "+command);

     

     

    3. 요청정보에 따라 필요한 모델 클래스를 인스턴스로 생성하여 처리메소드 호출

     

    => 모델 클래스의 처리 메소드의 호출결과(반환값 - 이동방식과 URL주소)를 반환받아 저장

     

    요청정보를 비교하여 모델 클래스로 인스턴스를 생성하여 참조변수에 저장

    모델 클래스의 인스턴스를 저장하기 위한 참조변수

    요청정보를 비교하여 모델 클래스로 인스턴스 생성하여 참조변수에 저장

     

     

    < 일반적으로 필요한 모델 클래스 예시 >

    ...더보기

    //로그인 입력페이지 : /loginForm.do - Model : LoginFormModel >> 포워드 이동(View : user_login.jsp)
    //로그인 처리페이지 : /logn.do - Model : LoginModel >> 리다이렉트 이동(/loginForm.do)
    //회원정보 입력페이지 : /writeForm.do - Model : WriteFormModel >> 포워드 이동(View : user_write.jsp)
    //회원정보 처리페이지 : /write.do - Model : WriteModel >> 리다이렉트 이동(/loginForm.do)
    //로그아웃 처리페이지 : /logout.do - Model : LogoutModel >> 리다이렉트 이동(/loginForm.do)
    //회원목록 출력페이지 : /list.do - Model : ListModel >> 포워드 이동(View : user_list.jsp)
    //회원상세 출력페이지 : /view.do - Model : ViewModel >> 포워드 이동(View : user_view.jsp)
    //회원변경 입력페이지 : /modifyform.do - Model : ModifyFormModel >> 포워드 이동(View : user_modify.jsp)
    //회원변경 처리페이지 : /modify.do - Model : ModifyModel >> 리다이렉트 이동(/view.do)
    //회원삭제 처리페이지 : /remove.do - Model : RemoveModel >> 리다이렉트 이동(/list.do)
    //에러메세지 출력페이지 : /error.do - Model : ErrorModel >> 포워드 이동(View : user_error.jsp)

     

    >> if절을 이용해 각 요청별로 처리해주면 되는데,

    아래 첫 번째 if절과 같이 각 조건마다 변수를 선언해주는 것은 비효율적이다.

     

    if(command.contentEquals("/loginForm.do")) {
      LoginFormModel model = new LoginFormModel();
      model.execute();
    } else if(command.contentEquals("/login.do")) {
      LoginModel model = new LoginModel();
      model.execute();
    }
    		 
    * ===> 이런 식으로 코드가 중복되는 것은 좋지 않다. 그러므로 하나의 변수를 만들어 여러 곳에서 쓸 수 있는 방법!!!
    * ===> '상속'을 이용한다. 인터페이스를 만들어야 한다.
    * ===> 다음과 같은 형식으로 만들어줄 수 있음
    
    Model model; --- if문 밖에 선언
    
    if(command.contentEquals("/loginForm.do)") {
    	model = new LoginFormModel();
    } else if(command.equals("/login.do")) {
    	model = new LoginModel();
    } else if(command.equals("/error.do")) {
    	action=new ErrorModel();
    } else {//요청정보가 존재하지 않을 경우 - 비정상적인 요청
    	action=new ErrorModel();
    }
    

     

     

     

    4. 반환받은 결과를 이용하여 페이지 이동

     

    *cf*불리언은 getter가 아니라 is메소드로 생성됨

    다른 웹 어플리케이션으로 JSP 문서의 제어권(스레드, 즉 프로그램의 흐름) 이동
    => 클라이언트 브라우저의 주소창에 변화가 없으며 request scope의 객체 공유

    ** request scope : 공유범위

    => 제어권을 이동하기 위한 RequestDispatcher 인스턴스를 반환
    => RequestDispatcher 인스턴스로 제어권을 이동하는 메소드

     

    if(actionForward.isForward()) {//포워드 이동
    
      //다른 웹 어플리케이션으로 JSP 문서의 제어권(스레드, 즉 프로그램의 흐름) 이동
      // => 클라이언트 브라우저의 주소창에 변화가 없으며 request scope의 객체 공유
      ** request scope : 공유범위
      //HttpServletRequest.getRequestDispatcher(String path)
      // => 제어권을 이동하기 위한 RequestDispatcher 인스턴스를 반환
      //RequestDispatcher.forward(ServletRequest Request, HttpServletResponser response)
      // => RequestDispatcher 인스턴스로 제어권을 이동하는 메소드
      request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
    
    } else {//리다이렉트 이동
    
      //클라이언트에게 URL 주소를 전달하여 재요청하도록 설정
      // => 클라이언트 브라우저의 주소창에 변화가 있으며 request scope의 객체 공유 불가능
      response.sendRedirect(actionForward.getPath());
    
    }

     

     

    tip : 모델2는 오류를 catch로 잡지 않고 throw SQLException으로 모두 던져버린다.

    (finally에서 close() 해줘야하기 때문에 try문은 유지)

     

     

    댓글

coding wanee