2020-7-4 스프링 MVC(1)

스프링 MVC

  • 모델 : 평범한 자바객체(POJO), 도메인객체 또는 DTO로 화면에 전달할 데이터를 가진 객체
  • 뷰 : HTML, JSP, 타임리프
  • 컨트롤러 : 스프링MVC. 사용자 입력을 받아 모델 객체의 데이터를 변경하거나 모델 객체를 뷰에 전달하는 역할
    • 입력값 검증
    • 입력 받은 데이터로 모델 객체 변경
    • 변경된 모델 객체를 뷰에 전달

@Controller
public class EventController {
    @Autowired
    private EventService eventService;

    @GetMapping("/events")
    public String events(Model model) {
        model.addAttribute("events", eventService.getEvents());
        return "events"; //view의 이름
    }
}

  • view의 이름인 events를 template디렉토리 밑에서 찾는다.

MVC패턴의 장점

  • 동시다발적개발 : 백엔드, 프론트가 독립적으로 개발 가능
  • 높은 결합도 : 논리적으로 관력있는 기능을 하나의 컨트롤러로 묶거나 특정 모델과 관련된 뷰를 그룹화할 수 있다.
  • 낮은의존도 : 뷰,모델,컨트롤러는 각각 독립적이다
  • 한모델에 대한 여러형태의 뷰를 가질 수 있다.

단점

  • 코드 네비게이션이 복잡
  • 코드 일관성 유지에 노력이 필요
  • 높은 학습곡선

서블릿 애플리케이션

  • 스프링MVC는 서블릿기반으로 웹 MVC를 손쉽게 해준다.

서블릿

  • 서블릿 애플리케이션을 직접실행할 수 없다. 서블릿 컨테이너를 사용해야한다.

  • 자바 엔터프라이즈 에디션은 웹애플리케이션 개발용 스펙과 API제공

  • 요청 당 쓰레드사용

  • 그중 가장 중요한게 HttpServlet

  • 서블릿이전에는 CGI(Common Gatewat Interface)를 이용하여 요청당 프로세스로 만들었다.

  • 장점

    • 빠르다
    • 플랫폼 독립적
    • 보안
    • 이식성
  • 서블릿 엔진 또는 서블릿컨테이너(톰캣, 제티, 언더토…)

    • 세션관리
    • 네트워크서비스
    • MIME기반 메세지 인코딩 디코딩
    • 서블릿 생명주기 관리
  • 서블릿 생명주기

    • 서블릿 컨테이너가 서블릿 인스턴스의 init()을 호출하여 초기화. 한번 초기화하고 나면 그 뒤로는 생략
    • 서블릿이 초기화된 다음. 클라이언트의 요청을 처리할 수 있다. 각 요청은 별도의 쓰레드로 처리하고 이때 서블릿 인스턴스의 service()를 호출.
      • 이 안에서 HTTP요청을 받고 HTTP응답을 만든다.
      • service()는 보통 HTTP메서드에 따라 doGet(), doPost() 등으로 처리를 위임. 따라서 보통 doGet(), doPost()를 구현한다.
    • 컨테이너의 판단에 따라 해당 서블릿을 메모리에서 내려할 시점에 destroy()를 호출한다.
  • public class HelloServlet extends HttpServlet {
    
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doGet");
        resp.getWriter().write("Hello Servlet");
      }
    
      @Override
      public void destroy() {
        System.out.println("destory");
      }
    
      @Override
      public void init() throws ServletException {
        System.out.println("init");
      }
    }
    
    
  • 가장원시적인 서블릿은 위의 클래스를 작성하고 그 작성한 서블릿을 web.xml에 직접 등록을 해줘서 사용을 해야됬다.

서블릿 리스너, 필터

서블릿리스너

  • 웹 애플리케이션에서 발생하는 주요 이벤트를 감지하고 각 이벤트에 특별한 작성이 필요한 경우에 사용할 수 있다.
    • 서블릿 컨텍스트 수준의 이벤트
      • 컨텍스트 라이프사이클 이벤트
      • 컨텍스트 애트리뷰트 변경 이벤트
    • 세션수준의 이벤트
      • 세션 라이프사이클 이벤트
      • 세션 애트리뷰트 변경 이벤트

서블릿필터

  • 들어온 요청을 서블릿으로 보내고, 또 서블릿이 작성한 응답을 클라이언트로 보내기 전에 특별한 처리가 필요한 경우에 사용할 수 있다.
  • 체인형태의 구조다. => 서블릿컨테이너와 서블릿 사이에 필터를 여러개 둘 수 있다. 체인은 순차적으로 동작한다.
  • doGet()으로 들어오기전에 필터로 처리.

web.xml에 리스너와 필터를 등록할 수 있다. 필터는 url-pattern과 servlet-name으로 등록할 수 있다.

context 생성 - 서블릿 생성 - doGet - 서블릿 종료 - context종료순으로 실행

서블릿 애플리케이션에서 스프링 연동하기

  • 서블릿에서 스프링이 제공하는 IoC컨테이너를 활용
  • 스프링이 제공하는 서블릿 구현체 DispatcherServlet사용하기

DispatcherServlet

  • 스프링 MVC의 핵심
  • Front Contrller역할을 한다. => 모든 요청을 하나로 받아서 해당요청을 처리할 핸들러에게 분배한다(dispatch)

DispatcherServlet

  • 초기화 : HandlerMapping(핸들러를 찾아주는 인터페이스), HandlerAdapter(핸들러를 실행하는 인터페이스), HadlerExceptionResolver, ViewResolver…등의 빈들을 탐색하고 초기화한다.
  • 동작순서
    • 요청을 분석(locale, theme, multipart…)
    • 핸들러 매핑에 위임하여 요청을 처리할 핸들러를 찾는다.
    • 등록되있는 핸들러 어댑터 중에 해당 핸들러를 실행할 수 있는 핸들러 어댑터를 찾는다.
    • 찾아낸 핸들러어댑터로 응답을 처리
    • 예외가 발생하면 예외처리핸들러에 위임
    • 핸들러의 리턴값을 보고 어떻게 처리할지 판단 => 뷰이름에 해당하는 뷰를 찾아서 모델데이터를 렌더링, @ReponseEntity가 있다면 Converter를 이용하여 응답본문을 만든다.
    • 최종응답을 보낸다.

스프링MVC 구성요소

  • DispatcherServlet은 다양한 인터페이스들을 구현하고 있다.
    • MultipartResolver : 파일업로드 요청처리, HttpServletRequest => MultipartHttpServletRequest로 변환해주어 File을 꺼낼 수 있는 API를 제공
    • LocaleResolver : 클라이언트 위치(Locale)정보를 파악, 기본전략은 요청의 accept-language를 보고한다.
    • ThemeResovler : 애플리케이션에 설정된 테마를 파악하고 변경. 특징에 따라 다른 CSS를 사용하는것.
    • *HandlerMapping : 요청을 처리할 핸들러를 찾는 인터페이스
    • *HandlerAdapter : 핸들러매핑이 찾아낸 핸들러를 처리, 스프링MVC확장력의핵심
    • *HandlerExceptionResolvers : 요청 처리 중에 발생한 에러처리
    • RequestToViewNameTranslator : 핸들러에서 뷰 이름을 명시적으로 리턴하지 않으면 요청을 기반으로 뷰 이름을 판단.
    • *ViewResolver : 뷰이름에 해당하는 뷰를 찾아내는 인터페이스
    • FlashMapManger : FlashMap인터페이스를 가져오고 저장, FlashMap은 주로 리다이렉션을 사용할때 매개변수를 사용하지 않고 데이터를 전달하고 정리할때 사용
  • DipstacherServlet 기본 전략 : DispatcherServlet.properties

정리

  • DispatcherServlet은 굉장히 복잡한 서블릿이다.

  • DispatcherServlet 초기화 : 특정타입에 해당하는 빈을 찾는다 => 없으면 기본전략을 사용(DispatcherServlet.properties)

  • 스프링부트를 사용하지 않는 스프링 MVC

    • 서블릿컨테이너(ex, 톰캣)에 등록한 웹 애플리케이션(WAR)에 DispatcherServlet을 등록한다. web.xml에 서블릿 등록 or WebApplicationInitializer에 자바코드로 등록. 빈에 뭐가 등록되있는지가 중요.

    • public class WebApplication implements WebApplicationInitializer {
          @Override
          public void onStartup(ServletContext servletContext) throws ServletException {
              AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
              context.register(WebConfig.class);
              context.refresh();
      
              DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
              ServletRegistration.Dynamic app = servletContext.addServlet("app", dispatcherServlet);
              app.addMapping("/app/*");
          }
      }
      // 스프링3.1, 서블릿3.0이상부터 지원
      
  • 스프링부트를 사용하는 스프링 MVC

    • 자바애플리케이션에 내장톰켓을 만들고 그 안에 DispatcherServlet을 등록 => 부트 자동설정이 자동으로 해준다.
    • 스프링부트의 주관에 따라 여러 인터페이스 구현체를 빈으로 등록한다.
Written on July 4, 2020