티스토리 뷰

책/스프링 인 액션

7장

IT공부블로그 2019. 4. 17. 13:52
728x90
반응형

AbstractAnnotationConfigDispatcherServletInitializer에 디스패처서블릿 추가설정을 위한 메소드들도 존재한다


그중 하나가 customizeRegistration이다


디스패처서블릿이 등록된다음 ServletRegistration 안에 전달하면서 customizeRegistration() 메소드를 호출


customizeRegistration를 오버라이딩 함으로써  디스패처서블릿에 추가설정을 적용한다



MultipartConfigElement를 설정하기위해 customizeRegistration 파라미터로 ServletRegistration.Dynamic이 기초 설정을 다하고 서블릿 3.0이상의 멀티파트를 설정하기위해 setMultipartConfig 메소드의 매개변수로 MultipartConfigElement를 주고 안에 파일경로를 설정한다



서블릿 필터 추가하기


서블릿과 필터를 더 추가하고싶을경우  자바에서의 장점은 초기화클래스를 사용자 마음대로 정의할수있다는것


어떤 컴포넌트를 추가한다음 WebApplicationlnitializer를 구현하면 된다



WebApplicationlnitializer는 필터, 리스너 등을 추가하는 일반적인 방법



필터를 등록하여 단순히 디스패처서블릿에 매핑 시킨다면 AbstractAnnotationConfigDispatcherServletInitializer를 사용하면된다


다수의 필터를 등록한다면  AbstractAnnotationConfigDispatcherServletInitializer의 getServletFilters()가 필요




getServletFilters는 몇개의 필터만 리턴할수도있고 리턴되면 자동으로 디스패처서블릿과 매핑이된다




web.xml로 java설정을 하려면 디스패처서블릿과 컨텍스트로더리스너에 AnnotationConfigWebApplicationContext를 사용할것을 명시해야한다


AnnotationConfigWebApplicationContext는 xml 대신 java 설정클래스를 로드하는 WebApplicationContext를 구현한 클래스이다.


멀티파트 폼 데이터 처리



DispatcherServlet에서 멀티파트 요청을 읽어 들이는 방법을 알려 주기 위한 멀티파트 리졸버를 설정해야 한다



디스패처 서블릿에는 멀티파트 데이터를 파싱하는것이 구현되어있지않으므로 멀티파트리졸버 인터페이스의 구현내용에서 결정하도록 되어있다



멀티파트 리졸버 종류


1. CommonsMultipartResolver : Jarkarta common FileUpload를 사용


2. StandardServletMultipartResolver : 서블릿 3.0 이상, 스프링 3.1 이상을 사용한 멀티파트 요청에대한 지원 


요새는 주로 2번을 사용 서블릿 컨테이너에 구현된것을 사용하기때문에 의존성이 없음


하지만 서블릿 3.0 이하, 스프링 3.1 이하라면 1번을 사용



StandardServletMultipartResolver를 구현하는데 인자같은게 필요하지않다



하지만 이렇게 할경우 여러 제약사항같은것을 추가하기힘들다



제약사항을 추가하기위해서 서블릿 설정에 멀티파트설정을 명시적으로 해줘야한다

최소한 업로드 동안 임시 패쓰를 잡아주지않으면  StandardServletMultipartResolver가 정상적으로 작동하지않는다 


더 구체적인사항은 디스패처서블릿을 초기화할때 web.xml or 서블릿 초기화 클래스에 명시해줘야한다



서블릿초기화 클래스에서 디스패처서블릿 등록시에 setMultipartConfig()를 호출하고 안에 MultipartConfigElement의 인스턴스를 전달할때 설정


AbstractAnnotationConfigDispatcherServletlnitializer or AbstractDispatcherServletlnitializer를 상속받은 초기화 클래스로 설정된 디스패처서블릿을 사용한다면 디스패처 서블릿의 인스턴스를 생성하거나 서블릿 컨텍스트로 직접 등록해줄필요없다 (알아서 생성해주니)


멀티파트 세부사항을 위해 customizeRegistration()를 오버라이딩 하는것은 가능하다



단일파라미터를 받는 생성자는 업로드시 임시로 저장할 절대패쓰를 받는다 이외의 추가설정 업로드 파일크키 등을 설정하려면 다양한 파라미터를 받는 생성자를 사용




임시 저장위치 절대패쓰, 업로드되는 파일의 최대크기, 전체 멀티파트 요청의 최대크기, 임시저장위치에 쓰지않고 업로드할수있는 파일 최대크기





web.xml을 사용하여 디스패처서블릿을 설정할때 멀티파트설정하는법


반드시 location부분의 설정을 해줘야한다 (최소한의 설정이기때문에)




Jakarta Commons Filellpload 멀티파트 리졸버 설정하기

서블릿 3.0 이상 컨테이너를 사용하지않으면 StandardServletMultipartResolver를 사용하지못하니 그 대안으로 Commons Filellpload를 사용한다


StandardServletMultipartResolver같이 임시저장위치를 지정하지않아도 기본 저장위치가 설정되어있기때문에 해주지않아도 된다 하지만 uploadTempDir 프로퍼티를 이용하여 다른 위치로 변경할수있다




uploadTempDir 프로퍼티를 이용한것처럼 다른 세부사항 설정도 가능하다




최대 파일사이즈는 2M 최대 인메모리는 0 으로설정

멀티파트 요청의 최대크기를 명시하는방법은 없다




멀티파트 요청 처리하기


업로드된 파일을 받아줄 컨트롤러 메소드가 필요하다

@RequestPart를 컨트롤러 메소드에 달아준다





기존 form과는 다르다 

enctype="multipart/form-data"는 기존의 form데이터를 전송하는게아닌 멀티파트 데이터를 전송한다


input file을 추가하여 사용자가 파일을 추가하게끔 하고

accept="image/jpeg,image/png,image/gif" accept를 지정하여 받을수있는 파일형식을 지정한다




업로드된 파일을 받기위해 @RequestPart가 붙은 바이트 배열을 하나 생성해준다

이제 사용자가 파일을넣어서 보내면 이 바이트배열에 저장된다  

사용자가 아무것도보내지않으면 빈값이 저장된다 (null은 아님)


이제 바이트배열에 저장된값이 어떤 파일타입인지, 원래 파일이름이 뭔지, 파일로 저장하는방법에 대해 알아본다




멀티파트 파일


바이트배열로 들어온 파일데이터를 처리하는건 간단하지만 제한적이다 


그래서 스프링에서는 멀티파트파일을 제공한다


사용자가 올린 파일의 이름, 크기, 타입을 알수있고 inputStream으로 파일데이터를 스트림형태로 읽어올수도있다 


transferTo는 파일시스템에쓰는것을 도와준다




파일을 저장하는것은 간단하지만 파일을 관리하는것은 사용자의 몫이다




부분으로 업로드된 파일 받기


서블릿 3.0이상의 컨테이너를 사용한다면 multipartfile 대안으로 part를 이용가능하다

스프링 MVC는 컨트롤러메소드의 파라미터로 javax.servlet.http.part를 받을수있다




멀티파트파일 == part 거의 같다


part와 멀트파트파일의 메소드명은 거의 동일하다


일부 다르지만 

getSubmittedFileName()은 getOriginalFileName()에 대응된다

write()는 transferTo()로 대응된다




만약 파일업로드를 처리하는 컨트롤러메소드의 파라미터를 part 인자통해 작성한다면 

StandardServletMulpartResolver를 사용하지않아도 된다


StandardServletMulpartResolver는 멀티파트파일로 동작할때만 필요



예외 처리하기


결과가 좋든 나쁘든 서블릿 요청이오면 서블릿 응답을 해주어야한다


예외를 응답시켜주는 방법

1. 몇가지 예외는 자동으로 http상태코드로 매핑됨

2. http상태코드로 매핑   http상태코드로 매핑하기위해서는 @ResponseStatus를 붙여줘야한다

3. 예외처리를 위한 메소드 @ExceptionHandler를 붙여준다



예외를 http상태코드에 매핑


스프링은 12개 정도의 예외를 자동으로 http상태코드로 매핑시킨다





내장 매핑예외는 디스패처서블릿의 동작 검증 수행과정에서의 오류에 대한 결과들이다

내장 매핑예외는 어플리케이션 예외에는 쓸모가없다


그래서 @ResponseState를 통해 매핑시켜주는 방법을 사용한다




위의 사진에서 findOne이 null을 반환하면  SpittleNotFoundException이 발생한다



SpittleNotFoundException은 안의 내용이 아무것도없다 이러한 경우 일반적으로 500에러가 발생한다

어디에도 매핑되지않는경우 예외가 발생하면 500에러가 발생한다


SpittleNotFoundException을 404에러 매핑시키는 방법은 아래와 같다




위와같이 설정하면 앞으로 404에러가 발생한다



예외 처리 메소드 작성하기


위 방식과같이 http상태코드를 띄우는것만아닌 더 많은 정보를 전달해야할경우 사용




위와 같이 해당클래스에서 예외발생시 처리할수있다



@ExceptionHandler 메소드는 예외발생시 go-to메소드로 지정한다

그리고 논리적인 뷰이름을 리턴한다


@ExceptionHandler는 해당 컨트롤러의 DuplicateSpittleException을 처리한다 

@ExceptionHandler는 해당 컨트롤러내의 모든 핸들러 메소드의 예외를 처리할수있다

이는 스프링 3.2부터 가능한 컨트롤러 어드바이스 클래스에서 정의된 경우만 해당



어드바이징 컨트롤러


@ExceptionHandler는 예외처리하기에 매우 유용하다 하지만 여러 클래스를 담당하기 위해서 중복된 @ExceptionHandler를 쓰기에는 부담이된다


스프링 3.2부터 제공하는 @ControllerAdvice는 다음 어노테이션이 붙은것을 포함한다


- @ExceptionHandler

- @InitBinder

- @ModelAttribute


@ControllerAdvice에 위 3개의 어노테이션이 붙은 메소드는 @RequestMapping이 붙은 모든 컨트롤러에 적용이됨


@ControllerAdvice 어노테이션에 @Component가 있어서 컴포넌트스캔에 의해 선택이됨


아래는 특정예외를 모든 컨트롤러에 적용시키는 방법





어떠한 컨트롤러에서 예외가 발생하여도 duplicateSpittleHandler() 가 호출되어 예외를 처리한다



리다이렉션되는 요청 간의 데이터 전달하기


컨트롤러에서 redirect로 시작하는 String값을 리턴하면 뷰이름과 같은걸 찾지않고 브라우저에게 바로 리다이렉션패쓰를 전달



요청시 핸들러메소드가 종료되기전에 데이터를 요청의 attribute에 복사한다

요청은 렌더링을 위해 뷰에 포워딩된다


컨트롤러에서의 요청과 뷰에서의 요청이 서로 같으므로 요청 애트리뷰트는 포워딩에도 살아남게된다





리다이렉션은 요청이 다시 시작되면 안의 모델이 모두 지워진다 그래서 모델을 유지하기 힘들다


하지만 리다이렉션을 처리하는 메소드에 데이터를 넘겨주는 방법이있다


1. 플래시 어트리뷰트 사용

2. url템플릿을 이용해 패쓰변수 or 쿼리인자로 넘겨줌



url템플릿을 이용해 넘기는방법




위와같이 템플릿을 이용해 넘겨줄수있다 템플릿부분을 사용자가 채워주면된다



위와 같이 Model데이터를 템플릿에 채워줄수있다

사용자에게 직접 입력받는 방식보다 훨씬 안전하다



쿼리파라미터를 이용한 방법



spitterld가 URL 플레이스 홀더에 매핑되지않았으므로 자동으로 쿼리인자가 붙는다


username 애트리뷰트가 habuma이고 spitterld 애트리뷰트가 42라면 결과적으로 리다이렉션

패스는 /spitter/habuma?spitterld=42다


패스변수, 쿼리파라미터로 전달하는것은 쉽고 직관적이긴하지만 간단한 숫자값, String값 같은값만 전달하는데 용이하다


더 복잡한것을 전달하기에는 적합하지않다 하지만 플래시 애트리뷰트는 다르다



플래시 애트리뷰트로 작업하기

String or 숫자가 아닌 객체데이터를 보내려면 플래시 애트리뷰트를 사용

모델에 넣은 데이터는 리다이렉션시 사라지기때문에 리다이렉션에도 안전한공간에 저장해야한다


세션에 넣는것도 하나의 방법이다. 하지만 스프링은 사용자가 세션에 있는 데이터를 잘 관리할꺼라 생각하지않는다 그래서 플래시어트리뷰트를 사용


플래시어트리뷰트는 다음 요청에게 전달하고 소멸한다




스프링 3.1에 추가된 RedirectAttribute를 이용한다

RedirectAttribute는 model도 제공하면서 플래시어트리뷰트도 제공한다


addFlashAttribute 메소드를 이용하여 추가한다


플래시어트리뷰는 리다이렉션 될시 세션에 복사되고 다시 요청이시작되면 세션에서 지워지면서 모델에 복사된다










728x90
반응형

' > 스프링 인 액션' 카테고리의 다른 글

5장  (0) 2019.04.13
3장  (0) 2019.03.20
스프링 인 액션 2장 빈 와이어링  (0) 2019.03.18
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함