The Debugging Chronicles : "코드의 미학"

Spring 프레임 워크 구조 _ FrontController (중요!!) 본문

Spring

Spring 프레임 워크 구조 _ FrontController (중요!!)

sweetseonah1004 2024. 8. 20. 02:23
"스프링 프레임워크의 구조"

 

1) 스프링

2) 전자 정부 프레임워크

3) 회사내의 스프링 기반 자체 프레임워크

=> 구조가 다 똑같다


실무에서는 MVC를 병렬적으로 코딩한다.

페이지가 이렇게 이루어 져있다고 하자

 

컨트롤러는 페이지를 두개 만들어야한다.

하나는 controller, 하나는 index이다

 

컨트롤러에는 html 코드가 없다는 점이다. 

근데 자바만 쓴다면 자바단에서 코딩하면 안될까? 라는 생각을 하게 되면서 시작한다.

.jsp 파일은 컴파일을 거쳐서 자바파일 중에서도 서블릿 파일이  된다

따라서 클래스 파일이 아닌 서블릿 파일로 만들어야한다.

contoller.jsp를 자바단에서 만들게 되면 이름을 FrontController라고 한다. (FC)

 

프레임워크 별로 부르는 이름이 다른다 homeController,dispatcher,dispatcherServlet라고 하는 곳도 있다.

중요한거는 구조에서 이러한 역할을 하는 것이 중요하다!

jsp에서 servlet으로 controller의 역할이 넘어왔다는 것이다.

 

FRONT는 요청을 처음받는 다는 뜻이다.

 

사용자가 하는 모든 요청이 일단 FrontController로 넘어올수 있도록 관리를 하는 것이 톰캣이다.

톰캣에서 서버 뿐만 아니라 웹설정까지 관리를 한다.

 

톰캣(servlet)에게 설정을 적용하는 방법은

 

1) xxx.xml (== 설정 파일) 등록   => web.xml

 

2).xml 파일은 스키마 분석도 어렵고 무겁다 그래서 가독성이 좋게 변경한  @annotation 등록, 활용

 


 

1.@WebServlet("*.do") => 어노테이션 웹서블릿

: 톰캣(server)이 구동 될 때, xxx.do로 끝나는 요청에 대하여 FC(FrontController)를 호출하게 됨

@WebServlet("*.do")
//어노테이션을 등록하면 서버 톰캣이 구동될때,xxx.do로 끝나는 요청에 대하여 FC를 호출하게됨 
//web.xml과 역할이 동일하다
// 두 곳에 하면 충돌이 일어나기 때문에 한곳에만 해야한다
public class FrontController extends HttpServlet {
	private static final long serialVersionUID = 1L;

 

2. doAction(request, response)함수 사용

요청이 get으로 오든 post로 오든 무조건 doAction을 실행하도록한다.

@WebServlet("*.do")
// 톰캣(server)이 구동될때, xxx.do로 끝나는 요청에 대하여 FC를 호출하게됨
public class FrontController extends HttpServlet {
	private static final long serialVersionUID = 1L;
   
   // 기본 생성자
    public FrontController() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request, response);
	}
	
	private void doAction(HttpServletRequest request, HttpServletResponse response) {
    
    }

 

 

3. 사용자의 모든 요청은 3단계로 진행하게 된다

(사용자 요청사항 추출 및 확인 ->  요청 사항 수행 -> 요청 사항 응답 (페이지 이동 등) )

 

어디 회사를 가든지 명칭은 다르더라도 동일한 구조, 단계로 진행된다.

 

1) 사용자가 무슨 요청 했는지 요청 사항을 분석해서 추출 및 확인

요청 정보는 'request'에 있다.

 

// 1. 사용자가 무슨 요청을 했는지 추출 및 확인
		
        // uri를 꺼내서 무슨 요청을 했는지 확인하다.
        // 프로젝트 + 파일 경로 가져옴
        String uri = request.getRequestURI();
        System.out.println("uri : "+uri);

 

 

uri 가 나온다.

필요한 뒷 부분만 자르기 위해서 contextPath로() - 디폴트 url주소로 자른다

 

String cp = request.getContextPath();
String command = uri.substring(cp.legnth);
System.out.println("comman : " + command);

 

commnad는 action number 혹은 menu number라는 의미

 

1번 전체 코드

 

2)요청을 수행

// 2.요청을 수행
if(command.equals("/main.do")){

}else if(command.equals("/login.do")){

}else if(command.equals("/join.do")){

}else{

}

 

index.jsp 에서 다음과 같이 요청을 받아왔는데

파라미터 때문에 무겁고 가독성도 좋지 않았는데

이제는 main.do로 보낸다.

그리고 예전 컨트롤러에서의 역할 들이 들어가야한다

// 2.요청을 수행
if(command.equals("/main.do")){
	// main.jsp에서 보여줘야하는 데이터들이 있나? 확인 해야한다
   	// 로그인 여부 - 세션에 저장되어 있어서 여기서 하면 안된다
    
    // 게시글 목록
    BoardDAO boardDAO = new BoardDAO();
    BoardDTO boardDTO = new BoardDTO();
    //ArrayList<BoardDTO> datas = new ArrayList<BoardDTO>();
    // 모델에서 받아와야하니까 아래와 같이 해아한다
    ArrayList<BoardDTO> datas = boardDAO.selectAll(boardDTO);
    request.setAttribute("게시글목록",datas);
    
    //main.jsp 페이지로 이동
}else if(command.equals("/login.do")){

}else if(command.equals("/join.do")){

}else{

}

 

근데 여기서

예전 코드와 비교와 하면 

예전에는 매번 4번씩 new를 해서 사용하진 않더라도 객체를 생성해줬다.

 

하지만 FrontController에서는 필요할 때만 객체를 생성을 했기 때문에 더 가볍다

그리고  더 직관적으로 어떤 객체가 필요하지 보인다.

 

// 2.요청을 수행
if(command.equals("/main.do")){
	// main.jsp에서 보여줘야하는 데이터들이 있나? 확인 해야한다
   	// 로그인 여부 - 세션에 저장되어 있어서 여기서 하면 안된다
    
    // 게시글 목록
    BoardDAO boardDAO = new BoardDAO();
    BoardDTO boardDTO = new BoardDTO();
    //ArrayList<BoardDTO> datas = new ArrayList<BoardDTO>();
    // 모델에서 받아와야하니까 아래와 같이 해아한다
    ArrayList<BoardDTO> datas = boardDAO.selectAll(boardDTO);
    request.setAttribute("게시글목록",datas);
    
    //main.jsp 페이지로 이동
    // 전달하게 있으니까 포워드
    //pageContext.forward("main.jsp);
    // 하지만 여기서 전달하지 않고 아래 3번에서 한번에 전달한다.
}else if(command.equals("/login.do")){

}else if(command.equals("/join.do")){

}else{

}

 

3) 요청 사항 응답

먼저 생각할꺼

전달할 데이터가 있는지 없는지 확인!!

있다면 포워드 , 없다면 리다이렉트!

그리고 어디로 가야하는지 , 즉 경로를 알아야한다.

   


 

더 나아가기

응집도 높이기!

 

 

 

로그인을 코딩한다고 하자

 

여기서는 예전에 setProperty가 해줬던 일을 일일이 넣어줘야한다

 

코드가 더 유리해 졌다. 작업은 많아 졌지만...

모델에서 무엇이 필요한지 더 직관적으로 보여진다.

 

그런데!!

컨트롤러 작업자가 여러명인데 한파일에서 코드를 고치면 불가능하다...

 

위의 현재 FC 코드는 응집도가 낮다.

응집도가 낮다는 것은 서로 관련 없는 코드들이 한 곳에  저장되어 있다는 뜻이다.

그러면 공동 작업이 어렵고 다른 곳에서 코드 작업 중이라면 해당 페이지 내용 전부 접근 및 이용이 불가능 하다.

 

가용성이 낮다....

대표적인 예가 은행권에서 사용자가 결제 안되는 시간이 있다... 

 

가용성이 낮아져서 사용자가 이용을 못하는 경우에는 반드시 그 사실을 고지한다!

 

자 이제 응집도를 높여보자

 

 

컨트롤러 중에 Board 관련 action은 

 

그리고 컨트롤러 중에 로그인 관련 액션은 

 

 

 

 

컨트롤러에 패키지를 기능별로 나눈다

XxxAciton.java 로 나눠서 관리할 수 있는데 이것이 바로 POJO 이다.

 

상대적으로 무거운 not POJO인 파일은 적을 수록 좋은데  이 파일은 하나만 존재한다

바로 FrontController이다

 

 

다시 mainAction으로 가보자

 

코드를 옮겨왔는데 코드를 함수 안에 써야하므로

그리고 mainAction 들은 밖에 있는 요청 정보들을 받아와서 수행하므로 인자가 필요하다

 

 

 그리고 FrontController에서 불러와 보자!

 

 

 

그런데 말입니다.. 여기서 조합을 하려고 보니 execute로 하지 않았다면... 바로 퇴출이다...

 

 

 

XxxAction들이 모두 메서드를  .execute(req,res)라고 강제하고 싶다면 바로 인터페이스를 사용한다.

 

그럼 이제 action류의 인터페이스를 만들러 가보자!!

 

 

 

그리고 implements 를 해준다

그러면 알아서 execute 메서드를 알아서 해준다

 

인터페이스 Action를 사용해야는 것이 핵심!!

 

 

근데 여기서 더 생각해보자!

자 그러면

결국에 요청들이 마지막에 무엇을 반환해야할까?

 

1. 어떻게 갈지? == 방식

2. 어디로 갈지? == 경로

 

이렇게 두가지를 반환해야한다.

 

그러면  Java에서 2개 이상 반환 뭘만들어야할까?

바로 클래스이다(DTO 같은 것)

 

그런 걸 바로 Action Forward라고 하는 것이다.!

 

 

 

 

인터페이스 action에서 무엇을 반환할지 넣어준다

 

다시 mainAction 으로 가보자

 

selectAll 해준 datas를 반환해줘야하니까  포워드를 해줘야하므로 false이다

 

로그아웃을 해보자

로그아웃은 보낼 데이터 없이 메인으로 보내야하므로

setRedirect를 true 해준다.

 


세션은 내장객체가 아니므로 request에서 꺼내서 사용해야한다.!

jsp에서는 내장이 되어서 바로 사용할 수 있지만 여기서는 POJO이기 때문에 가져다 써야한다.


이제는 

FrontController로 가보자