(Spring)관심사의 분리 및 MVC패턴

1. 관심사의 분리

위의 코드는 요일을 출력해주는 코드로 크게 세 가지 영역으로 나눌 수 있다.
입력을 처리하는 부분, 입력받은 날짜를 가지고 요일을 계산하는 부분(실제 작업 처리), 계산한 결과를 출력하는 부분
이 하나하나를 관심사(concern)이라 부른다.
즉 main이라는 메서드는 3개의 관심사를 가지고 있다고 할 수 있다.
OOP 5대 설계 원칙(SOLID) 중 첫 번째인 SRP(단일 책임원칙)에 의하면 '하나의 메서드는 하나의 책임만 진다'라는 뜻을 가진다. 여기서 책임은 관심사라 할 수 있다.
하지만 지금 위의 코드는 하나의 메서드에 세 가지의 관심사가 포함되어 있으므로 분리를 시켜줄 필요가 있다.
객체지향적으로 좋은 설계를 하려면 분리를 잘해야 한다.
분리는 아래의 3가지를 기준으로 한다.
1️⃣ 관심사의 분리
2️⃣ 변하는 것과 잘 변하지 않는 것의 분리
3️⃣ 공통코드의 분리 <중복의 제거>
2. 공통 코드의 분리 - 입력의 분리

대부분의 컨트롤러는 입력, 처리, 출력으로 되어있다.
입력 부분은 대부분 request.getParameter()를 많이 사용하므로 3개의 컨트롤러가 중복이 된다.
그러므로 입력부분을 하나로 때어서 앞에다 하나만 둔다.(공통 코드로 만들기)
그러면 요청을 받았을 때 입력을 먼저 처리하고 해당 컨트롤러에게 넘겨준다.
이렇게 함으로써 하나의 관심사가 분리되게 된다.
위와 같이 할 수 있는 이유는 입력 부분은 모든 컨트롤러가 비슷하기 때문에 따로 하나로 분리시킬 수 있는 것이다.
3. 출력(view)의 분리

관심사가 분리되지 않았을 때는 하나의 메서드 안에 있었기 때문에 입력 부분에서 받은 year, month, day를 처리, 출력 부분에서 사용할 수 있었다.
하지만 별도의 메서드로 분리되게 되면 더 이상 위의 변수들을 읽어 올 수 없다.
그렇기 때문에 중간 다리 역할을 하는 개체가 하나 필요한데 그 역할을 Model이라는 객체가 대신한다.
즉 Model이란 분리된 두 코드 간의 데이터 전송을 위해 쓰이는 객체다.
처리하는 부분에서는 Model객체에 결과에 필요한 값들을 다 저장한다.
이후 Model을 출력하는 부분에 전달을 해주면 객체에 담긴 내용들을 읽어서 출력을 만들어 낼 수 있다.
위와 같이 처리하는 부분을 Controller, 출력하는 부분을 View, 이 둘 간의 데이터를 주고받을 수 있는 객체가 Model이라고 하여 MVC 패턴이라고 한다.
📒스프링 MVC의 구조(단순화)
밑의 과정보다 실제 스프링의 동작 방식은 훨씬 복잡하지만 큰 맥락에서 간단하게만 살펴보자.
1. 스프링 MVC에서는 사용자의 요청이 들어오면 앞에서 입력 처리를 하는데 그 입력 처리를 담당하는 클래스가 DispatcherServlet이다.
2. DispatcherServlet이 입력을 처리한 후 해당 컨트롤러에게 요청과 Model 객체를 넘겨준다.
3. 컨트롤러는 요청을 처리하고 그 결과를 Model에 저장하여 DispatcherServlet에게 다시 주면 View에게 전달해 준다.
View에서는 작업 결과를 읽어서 응답을 만들어내어 클라이언트에게 전송한다.
Model에 담기는 값은 key, value 형태로 담긴다.
컨트롤러에서 DispatcherServlet으로 작업 결과를 넘길 때 View의 이름을 String값으로 넘긴다.
View의 이름만 String으로 return 하였는데 어떻게 스프링은 View를 찾는지 살펴보자

Spring프로젝트의 폴더를 살펴보면 [webapp] → [spring] → [appServlet] → servlet-context.xml파일이 위치한다.

파일을 열어보면 위와 같은 코드가 있는데 이 부분이 view의 경로를 지정하는 코드이다.
View이름을 리턴 받으면 접두사로 /WEB-INF/views를 붙이고 view의 이름이 온 후 접미사로 확장자인. jsp가 붙게 된다.
이처럼 InternalResourceViewResolver에 의해서 뷰의 경로와 확장자가 붙게 된다.
1️⃣ 메서드의 반환타입을 void로 하였을 경우

그리고 만약 위와 같이 메서드의 반환 타입을 String이 아닌 void로 하고 return값을 없앤다면 @RequestMapping에 매핑된 URL에 의해서 View의 이름이 결정된다❗
즉 매핑된 URL이름인 getYoilMVC.jsp가 응답된다.
보통 이렇게 쓰지 않지만 가능하다는 점만 유의하자.
2️⃣메서드의 반환타입을 ModelAndView로 하였을 경우

반환 타입을 ModelAndView로도 가능하다.
ModelAdnView란 Model과 View를 합친 것을 말한다.
1. Dispatcher로 부터 받던 매개변수 Model을 지우고 Controller에서 ModelAndView를 생성한다.
2. Model에서 데이터를 저장할 때는 addAttribute였지만 ModelAndView에서는 addObject를 사용하여 데이터를 저장한다.
3. 결과를 보여줄 View를 지정하기 위해 setViewName() 메서드를 사용하여 보여줄 View의 이름을 지정한다.
4. 마지막으로 ModelAndView를 DispatcharServlet에게 리턴한다.
메서드는 하나의 값만 반환할 수 있지만 Model과 View를 담을 객체를 만들고 객체를 리턴한다.
ModelAndView는 잘 사용하지 않고 보편적으로 컨트롤러에서 DispatcherServlet으로 부터 매개변수로 Model을 주입받아 데이터를 저장하고 View의 이름을 리턴하는 방식을 많이 사용한다.
Reference
'스프링의 정석 : 남궁성과 끝까지 간다' 수강 후 복습한 내용입니다.