1. 관심사의 분리 (Separation of Concerns)

[YoilTeller.java]
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTeller { 
    // public static void main(String[] args) {
        @RequestMapping("/getYoil")
        public void main(HttpServletRequest request, HttpServletResponse response) throws IOException{
        // 1. 입력
        String year = request.getParameter("year");
        String month = request.getParameter("month");
        String day = request.getParameter("day");

        // 2. 작업
        int yyyy = Integer.parseInt(year);
        int mm = Integer.parseInt(month);
        int dd = Integer.parseInt(day);

        Calendar cal = Calendar.getInstance();
        cal.set(yyyy, mm - 1, dd);

        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
        char yoil = "일월화수목금토".charAt(dayOfWeek);

        // 3. 출력
        response.setContentType("text/html"); // response 객체 형식을 적어야한다. 즉, 출력할 내용의 타입을 적어야한다.
        response.setCharacterEncoding("UTF-8"); // 텍스트도 인코딩을 해야지 한글이 깨지지 않는다.
        PrintWriter out = response.getWriter(); // response객체에서 브라우져로의 출력 스트림을 얻는다.
        out.println(year + "년" + month + "월" + day + "일은 "); 
        // 원래 제대로 하려면 HTML 형식을 갖춰서 해야한다.
        out.println(yoil + "요일입니다.");
    }
}

관심사는 해야할 작업이라 생각하면 된다.
객체 지향적으로는 코드 분리를 잘해야한다.
현재 위의 [YoilTeller.java]파일에서 main이라는 메소드는 3개의 관심사가 있다.
즉 OOP 5대 설계원칙(SOLID)에 부합하는 코드로 보면, 좋은 코드는 아니다.
(SOLID는 추후에 계속 설명) SOLID의 S는 SRP는 단일 책임 원칙이다.
단일 책임(관심사)의 원칙은 "하나의 메소드는 하나의 책임만 진다"는 뜻이다.
즉 3개의 관심사를 분리해야한다.

분리

  • 관심사의 분리
  • 변하는 것과 변하지 않는 것의 분리 (common, uncommon = 자주 변하는 것과 아닌 것)
  • 공통코드(중복코드)

작성한 코드를 보고, 3가지 분리사항에 부합하는지 보면 객체 지향적으로 잘 분리된 코드로 볼 수 있다.

2. 공통 코드의 분리 - 입력의 분리

각각의 입력부분을 떼어서, 공통코드로 한 곳으로 분류한다.

@RequestingMapping("/getYoil")
public void main(HttpServletRequest request, HttpServletRespons)

String을 int로 쓸 수도 있다.
(YoilTellerMVC.java 참고) 자동변환도 된다.
공통코드를 분리함으로써, 하나의 관심사가 사라지게 된다.

3. 출력(view)의 분리 - 변하는 것과 변하지 않는 것의 분리

[Spring MVC]

사용자의 요청이 들어오게 되면, 앞에서 입력처리를 한다. (DispatcherServlet),
DispatcherServlet 입력 처리 후에 해당 Controller에게 넘겨준다.
Controller는 처리한 결과를 Model 객체를 하나 만든 뒤에 값들을 다 저장하고 DispatcherServlet이 Model을 View에 전달한다.
View는 작업 결과를 읽어서, 응답을 만들어 낸 뒤에, 클라이언트에게 전송하게 된다.
이것이 Spring MVC 패턴이다.

4. MVC 패턴

View를 Controller와 분리하게 되면, 상황에 맞는 View를 보여주기 편리해진다.
그렇기에 아래의 경우에는 yoil.jsp와 yoilError.jsp 로 구분했다.

[YoilTellerMVC.java]
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC { 
        @RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
        public String main(int year, int month, int day, Model model) throws IOException{
        // String을 int로 변경, 반환타입은 String으로 변경

            // 1. 유효성 검사 필요
            if(isValid(year, month, day))
                return "yoilError"; // WEB_INF/views/yoilError.jsp = 에러시에 나오는 view

            // 2. 요일 계산
            char yoil = getYoil(year, month, day);

            // 3. 계산한 결과를 Model에 저장
            model.addAttribute("year", year);
            model.addAttribute("month", month);
            model.addAttribute("day", day);
            model.addAttribute("yoil", yoil);

            return "yoil"; // WEB_INF/views/yoil.jsp
    }

        private boolean isValid(int year, int month, int day) {
            // 클래스 내에서만 쓰기에 private
            return true;
        }

        private char getYoil(int year, int month, int day) {
            Calendar cal = Calendar.getInstance();
            cal.set(year, month - 1, day);

            int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
            return "일월화수목금토".charAt(dayOfWeek);
        }
}
[yoil.jsp]
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
    <title>yoil</title>
</head>
<body>
<P> ${year }년 ${month }월 ${day }일은 ${yoil }입니다. </P>
</body>
</html>
[yoilError.jsp]
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
    <title>yoilError</title>
</head>
<body>
<P>  잘못된 요청입니다.<br>
    년, 월, 일을 모두 올바르게 입력해주세요. </P>
</body>
</html>

[servlet-context.xml]

src/main/webapp/WEB-INF/spring/appServlet 에 있는 servlet-context.xml에 적혀있는 것이다.
아래 코드 때문에, 접두사나 접미사에 경로나 확장자가 붙는 것이다.

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
</beans:bean>

5. ModelAndView

// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC { 
        @RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
        public ModelAndView main(int year, int month, int day) throws IOException{
            // 반환타입을 ModelAndView로 변경
            // 1. model and view의 경우
            ModelAndView mv = new ModelAndView();

            // 2. 유효성 검사
             if(!isValid(year, month, day))
                 return mv;

            // 3. 작업
            char yoil = getYoil(year, month, day);

            // 4. 작업 결과를 ModelAndView에 저장
            mv.addObject("year", year);
            mv.addObject("month", month);
            mv.addObject("day", day);
            mv.addObject("yoil", yoil);

            // 5. 결과를 보여줄 view를 지정
            mv.setViewName("yoil"); // view의 이름을 지정 // WEB_INF/views/yoil.jsp
            return mv;
    }
}

6. 컨트롤러 메서드의 반환타입

  • [String]인 경우 = 뷰 이름을 반환
  • [void]인 경우 = 맵핑된 url의 끝 단어가 뷰 이름
  • [ModelAndView]인 경우 = Model과 뷰 이름을 반환

'Java, Spring > 개념정리' 카테고리의 다른 글

DI(Dependency Injection)  (0) 2023.01.12
DI, IoC, Container  (0) 2023.01.10
액션태그  (0) 2022.08.16
디렉티브 태그  (0) 2022.08.15
스크립트태그  (0) 2022.08.15

+ Recent posts