Skip to content

Latest commit

 

History

History
419 lines (316 loc) · 17.8 KB

Spring-웹MVC-강의-정리.md

File metadata and controls

419 lines (316 loc) · 17.8 KB

Spring 웹 MVC 강의 정리

백기선의 Spring 웹 MVC를 정리한 자료입니다.

서블릿

  • 자바 엔터프라이즈 에디션은 웹 애플리케이션 개발용 스팩과 API 제공
  • 요청 당 쓰레드(만들거나, 풀에서 가져옴) 사용
  • 그 중에 가장 중요한 클래스중 하나가 HttpServlet

서블릿의 장점(CGI 에비해)

  • 빠르다
  • 플랫폼 독립적
  • 보안
  • 이식성

서블릿 엔진 또는 서블릿 컨테이너(톰캣, 제티, 언더토)

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

서블릿 생명주기

  • 서블릿 컨테이너가 서블릿 인스턴스의 init() 메서드를 호출하여 초기화 한다.
    • 최초 요청을 받았을 때 한번 초기화 하고 나면 그 다음 요청부터는 이 과정을 생략해도된다.
  • 서블릿 초기화 된 다음부터는 클라이언트의 요청을 처리할 수 있다. 각 요청은 별도의 스레드로 처리하고 이 때 서블릿 인스턴스의 service()메서드를 호춣한다.
    • 이 안에서 HTTP 요청을 받고 클라이언트로 보낼 때 HTTP 응답을 만든다
    • service()는 보통 HTTP Method에 따라 doGet(), doPost() 등으로 처리를 위임한다.
  • 서블릿 컨테이너의 판단에 따라 해당 서블릿 메모리에서 내려와 할 시점에 destroy()를 호출한다.

서블릿 리스너와 서블릿 필터

서블릿 리스너

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

서블릿 필터

  • 들어온 요청을 서블릿으로 보내고, 또 서블릿이 작성한 응답을 클라이언트로 보내기 전에 특별한 처리기가 필요한 경우에 사용 할 수 있다.
  • 체인 형태의 구조

DispatherServlet

DispatherServlet 동작 원리

DispatherServlet 초기화

  • 아래의 특별한 타입의 빈을 찾거나, 기본 전략에 해당하는 빈을 등록한다.
    • HandlerMapping(핸들러를 찾아주는 인터페이스), HanlderAdpater(핸들러를 실행하는 인터페이스), HanlderExceptionResolver, ViewResolver, ....

DispatherServlet 동작 순서

  1. 요청을 분석한다. (로케일, 테마, 멀티파크 등등)
  2. (핸들러 매핑에게 위임하여) 요청을 처리할 핸들러를 찾는다.
  3. (등록되어 있는 핸들러 어뎁터중) 해당 핸들러를 실핼 할 수 있는 "핸들러 어뎁터"를 찾는다.
  4. 찾아낸 "핸들러 어뎁터"를 사용해서 핸들러의 응답을 처리한다.
  5. (부가적으로) 예외가 발생했다면, 예외 처리 핸들러에 요청 처리를 위임한다.
  6. 핸들러의 리턴값을 보고 어떻게 처리할지를 판단한다.
    • 뷰 이름에 해당하는 뷰를 찾아 모델 데이터를 렌더링 한다.
    • @ResponseBody가 있다면 Convter를 이용해서 응답 본문을 만든다.
  7. 최종적으로 응답을 보낸다.

DispatherServlet 구성 요소

  • DispatcherSerlvet의 기본 전략
    • DispachersServlet.propertes 설정을 따라간다.
  • MutilpartResolver
    • 파일 업로드 요청 처리에 필요한 인터페이스
    • HttpServletRequest를 MutilpartHttpServletRequest로 변환해주어 요청이 담고 있는 Fild을 꺼낼수 있는 API 제공
  • LocaleReslver
    • 클라이언트의 위치 정보를 파악하는 인터페이스
    • 기본 전략은 요청 accept-language를 보고 판단.
  • HanderMapping
    • 요청을 처리할 핸들러를 찾는 인터페이스
  • HandlerAdapter
    • HandlerMapping이 찾아낸 핸들러를 처리하는 인터페이스
    • 스프링 MVC 확장력의 핵심
  • HanderAdapter
    • HanlderMapping이 찾아낸 "핸들러" 처리하는 인터페이스
  • ViewResolver
    • 뷰 이름에 해당하는 뷰를 찾아내는 인터페이스
  • FlashMapManager
    • FlashMap 인스턴스를 가져오고 저장하는 인터페이스
    • FlashMap은 주로 리다이렉션을 사용할 때 요청 매개변수를 사용하지 않고 데이터를 전달하고 정리할 때 사용한다.
    • redirect:/events

MVC 설정

  • WebMvcConfigurationSupport.class
  • WebMvcAutoConfiguration.class
  • 설정을 기본 설정이다

스프링 부트 MVC 설정

  • 스프링 부트의 주관이 적용된 자동 설정이 동작한다.
    • JSP 보다 Thymeleaf 선호
    • JSON 지원
    • 정적 리소스 지원 (+ 웰컴 페이지, 파비콘 등 지원)
      • resourceHanderMapping을 기본으로 제공
  • 스프링 MVC 커스터마이징
    • application.properties
    • @Configuration + Implements WebMvcConfigurer: 스프링 부트의 스프링 MVC 자동설정 + 추가 설정
    • @Configuration + @EnableWebMvc + Imlements WebMvcConfigurer: 스프링 부트의 스프링 MVC 자동설정 사용하지 않음.

WebMvcConfigurer 설정

Formatter

public class PersonFormatter  implements Formatter<Person> {

    @Override
    public Person parse(String name, Locale locale) {
        return new Person(name, name);
    }

    @Override
    public String print(Person person, Locale locale) {
        return person.toString();
    }
}

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new PersonFormatter());
    }
}

@RestController
@RequestMapping("/sample")
public class SampleApi {

    @GetMapping("/{name}")
    public Person sample(@PathVariable("name") Person person) {
        return person;
    }
}
  • Formatter를 등록하면 PathVariable 어노테이션으로 받을 수 있다.

handlerIntercepter

  • preHandle을 통해서 전처리 가능
  • postHandler을 통해 후처리 가능
  • afterComplection 완전히 끝난 이후
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SimpleInterceptor()).order(0);
        registry.addInterceptor(new SecondeInterceptor()).order(1);
    }
}

public class SimpleInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("pre handler 1");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("post handler 1");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("after completion 1");
    }
}

    /**
     * preHandle 1 -> 요청 전처리
     * preHandle 2 -> 요청 전처리
     * postHandler 2-> 요청 후처리
     * postHandler 1-> 요청 후처리
     * 뷰 랜더링
     * afterCompletion 2 -> 
     * afterCompletion 1 -> 
     */

@GetMapping("/{name}")
public Person sample(@PathVariable("name") Person person) {
    return person;
}
  • postHandler, afterCompletion 순서는 preHandle와 반대이다.
  • new SimpleInterceptor()).order(0) 우선순위를 설정을 통해서 조절할 수 있다. (낮을 수록 우선순위가 높다. 음수도 가능하다)

boolean preHandle(request, response, handler)

  • 핸들러 실행하기 전에 호출 됨
  • 핸들러에 대한 정보를 사용할 수 있기 때문에 서블릿 필터에 비해 보다 세밀한 로직을 구현할 수 있다.
  • 리턴값으로 계속 다음 인터셉터 또는 핸들러로 요청,응답을 전달할지(true) 응답 처리가 이곳에서 끝났는지(false) 알린다.

void postHandle(request, response, modelAndView)

  • 핸들러 실행이 끝나고 아직 뷰를 랜더링 하기 이전에 호출 됨
  • 에 전달할 추가적이거나 여러 핸들러에 공통적인 모델 정보를 담는데 사용할 수도 있다.
  • 이 메소드는 인터셉터 역순으로 호출된다.
  • 비동기적인 요청 처리 시에는 호출되지 않는다.

void afterCompletion(request, response, handler, ex)

  • 요청 처리가 완전히 끝난 뒤(뷰 랜더링 끝난 뒤)에 호출 됨
  • preHandler에서 true를 리턴한 경우에만 호출 됨
  • 이 메소드는 인터셉터 역순으로 호출된다.
  • 비동기적인 요청 처리 시에는 호출되지 않는다.

vs 서블릿 필터

  • 서블릿 보다 구체적인 처리가 가능하다.
  • 서블릿은 보다 일반적인 용도의 기능을 구현하는데 사용하는게 좋다. 반대로 스프링에 특화된 기능을 구현해야 할 때는 handlerIntercepter으로 처리한다

ResourceHanlder

이미지, 자바스크립트, CSS, HTML 파일과 같은 정적인 리소스를 처리하는 핸들러 등록하는 방법

  • Default Servlet

    • 서블릿 컨테이너가 기본으로 제공하는 서블릿으로 정적인 리소스를 처리할 때 사용한다
  • 스프링 MVC 리소스 핸들러 매핑 등록

  • 가장 낮은 우선 순위로 등록

    • 우리가 직접만든 핸들러가 우선순위가 더 높아야 하기 때문에 우선순위가 낮아야한다.
    • 핸뜰러 매핑이 "/" 이하 요청을 처리하도록 하고
    • 최정적으로 리스스 핸들러가 처리하도록 한다.
  • 리소스 핸들러 설정

    • 어떤 요청 패턴을 지원할 것인가?
    • 어디서 리소스를 찾을 것인가?

Http Message Converter

  • 요청 본문에서 메시지를 읽어들이거나(@RequestBody), 응답 본문에 메시지를 작성할 때(@ResponseBody) 사용한다.
// 이렇게 등록하게 된 경우 스프링 부트에서 지정하는 WebMvcAutoConfiguration 기본 설정에서 등록한 http message converter를 덮어 씌어서 기존에 있는 컨버터를 삭제하고 추가한것으로 덮어 씌어진다. 사용하지 않는 것이 좋아 보인다.
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

}

// 이렇게 등록하면 기존에 있는 메시지 컨버터에 추가만 하는 형식이라서 안전하다.
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

}

기본 HTTP 메시지 컨버터

  • 바이트 배열 컨버터
  • 문자열 컨버터
  • Resource 컨버터
  • Form 컨버터 (폼 데이터 to/from MultiValueMap<String, String>)
  • (JAXB2 컨버터)
  • (Jackson2 컨버터)
  • (Jackson 컨버터)
  • (Gson 컨버터)
  • (Atom 컨버터)
  • (RSS 컨버터)

설정 방법

  • 기본으로 등록해주는 컨버터에 새로운 컨버터 추가하기: extendMessageConverters
  • 기본으로 등록해주는 컨버터는 다 무시하고 새로 컨버터 설정하기: configureMessageConverters
  • 의존성 추가로 컨버터 등록하기 (가장 일반적이다.)
    • 메이븐 또는 그래들 설정에 의존성을 추가하면 그에 따른 컨버터가 자동으로 등록 된다.
    • WebMvcConfigurationSupport 기본 설정을 따라 간다.
    • HttpMessageConverter로 @Bean을 등록한다(굳이 커스텀 해야 한다면 이게 제일 좋아 보인다.)

그밖에 WebMvcConfigurer 설정

  • CROS 설정
  • 리턴 값 핸들러 설정 : 스프링 MVC가 제공하는 기본 리턴 값 핸들러 이외에 리턴 핸들러를 추가 할 수 있다.
  • 아큐먼트 리졸버 설정 : 스프링 MVC가 제공하는 기본 아규먼트 리졸버 이외에 커스텀한 아규먼트 리졸버를 추가하고 싶을 때 설정한다.
  • 뷰 리졸버 설정 : 핸들러에서 리턴하는 뷰 에대한 리졸버이다. 타임리프, JSP 등 다양하게 있다.
  • Content Negotiation 설정 : 요청 본문 또는 응답 본문을 어떤 (MIME) 타입으로 보내야 하는지 결정하는 전략을 설정한다

MVC 설정 마무리

출처 배기선님 스프링 웹 MVC 공개 자료

@EnableWebMvc

  • 애노테이션 기반의 스프링 MVC 설정 간편화
  • WebMvcConfigurer가 제공하는 메소드를 구현하여 커스터마이징할 수 있다.

스프링 부트

  • 스프링 부트 자동 설정을 통해 다양한 스프링 MVC 기능을 아무런 설정 파일을 만들지 않아도 제공한다.
  • WebMvcConfigurer가 제공하는 메소드를 구현하여 커스터마이징할 수 있다.
  • @EnableWebMvc를 사용하면 스프링 부트 자동 설정을 사용하지 못한다.

스프링 MVC 설정 방법

  • 스프링 부트를 사용하는 경우에는 application.properties 부터 시작.
  • WebMvcConfigurer로 시작
  • @Bean으로 MVC 구성 요소 직접 등록

MVC 활용

요청 맵핑하기 6부 커스텀 애노테이션

출처 : 백기선의 스프링 웹 MVC

@RequestMapping 애노테이션을 메타 애노테이션으로 사용하기

  • @GetMapping 같은 커스텀한 애노테이션을 만들 수 있다.

메타(Meta) 애노테이션

  • 애노테이션에 사용할 수 있는 애노테이션
  • 스프링이 제공하는 대부분의 애노테이션은 메타 애노테이션으로 사용할 수 있다.

조합(Composed) 애노테이션

  • 한개 혹은 여러 메타 애노테이션을 조합해서 만든 애노테이션
  • 코드를 간결하게 줄일 수 있다.
  • 보다 구체적인 의미를 부여할 수 있다.

@Retention

  • 해당 애노테이션 정보를 언제까지 유지할 것인가.
  • Source: 소스 코드까지만 유지. 즉, 컴파일 하면 해당 애노테이션 정보는 사라진다는 이야기.
  • Class: 컴파인 한 .class 파일에도 유지. 즉 런타임 시, 클래스를 메모리로 읽어오면 해당 정보는 사라진다.
  • Runtime: 클래스를 메모리에 읽어왔을 때까지 유지! 코드에서 이 정보를 바탕으로 특정 로직을 실행할 수 있다.

@Target

  • 해당 애노테이션을 어디에 사용할 수 있는지 결정한다.

@Documented

  • 해당 애노테이션을 사용한 코드의 문서에 그 애노테이션에 대한 정보를 표기할지 결정한다.

메타 애노테이션

핸들러 메소드 6부 @Validated

출처 : 백기선의 스프링 웹 MVC

  • 스프링 MVC 핸들러 메소드 아규먼트에 사용할 수 있으며 validation group이라는 힌트를 사용할 수 있다.
  • @Valid 애노테이션에는 그룹을 지정할 방법이 없다.
  • @Validated는 스프링이 제공하는 애노테이션으로 그룹 클래스를 설정할 수 있다.

핸들러 메소드 12부: Flash Attributes

출처 : 백기선의 스프링 웹 MVC

주로 리다이렉트시에 데이터를 전달할 때 사용한다.

  • 데이터가 URI에 노출되지 않는다.
  • 임의의 객체를 저장할 수 있다.
  • 보통 HTTP 세션을 사용한다.

리다이렉트 하기 전에 데이터를 HTTP 세션에 저장하고 리다이렉트 요청을 처리 한 다음 그 즉시 제거한다.

RedirectAttributes를 통해 사용할 수 있다.

핸들러 메소드 15부: @RequestBody & HttpEntity

출처 : 백기선의 스프링 웹 MVC

@RequestBody

  • 요청 본문(body)에 들어있는 데이터를 HttpMessageConveter를 통해 변환한 객체로 받아올 수 있다.
  • @Valid 또는 @Validated를 사용해서 값을 검증 할 수 있다.
  • BindingResult 아규먼트를 사용해 코드로 바인딩 또는 검증 에러를 확인할 수 있다.

HttpMessageConverter

  • 스프링 MVC 설정 (WebMvcConfigurer)에서 설정할 수 있다.
  • configureMessageConverters: 기본 메시지 컨버터 대체
  • extendMessageConverters: 메시지 컨버터에 추가
  • 기본 컨버터
    • WebMvcConfigurationSupport.addDefaultHttpMessageConverters

HttpEntity

  • @RequestBody와 비슷하지만 추가적으로 요청 헤더 정보를 사용할 수 있다.

모델: @ModelAttribute 또 다른 사용법

출처 : 백기선의 스프링 웹 MVC

@ModelAttribute의 다른 용법

  • @RequestMapping을 사용한 핸들러 메소드의 아규먼트에 사용하기 (이미 살펴 봤습니다.)
  • @Controller 또는 @ControllerAdvice (이 애노테이션은 뒤에서 다룹니다.)를 사용한 클래스에서 모델 정보를 초기화 할 때 사용한다.
  • @RequestMapping과 같이 사용하면 해당 메소드에서 리턴하는 객체를 모델에 넣어 준다. RequestToViewNameTranslator

예외 처리 핸들러: @ExceptionHandler

출처 : 백기선의 스프링 웹 MVC

특정 예외가 발생한 요청을 처리하는 핸들러 정의

  • 지원하는 메소드 아규먼트 (해당 예외 객체, 핸들러 객체, ...)
  • 지원하는 리턴 값
  • REST API의 경우 응답 본문에 에러에 대한 정보를 담아주고, 상태 코드를 설정하려면 ResponseEntity를 주로 사용한다.

참고

전역 컨트롤러: @(Rest)ControllerAdvice

출처 : 백기선의 스프링 웹 MVC

예외 처리, 바인딩 설정, 모델 객체를 모든 컨트롤러 전반에 걸쳐 적용하고 싶은 경우에 사용한다.

  • @ExceptionHandler
  • @InitBinder
  • @ModelAttributes

적용할 범위를 지정할 수도 있다.

  • 특정 애노테이션을 가지고 있는 컨트롤러에만 적용하기
  • 특정 패키지 이하의 컨트롤러에만 적용하기
  • 특정 클래스 타입에만 적용하기

참고