본문으로 바로가기

[Spring] 스프링 웹 MVC - 3

category Spring 2021. 8. 2. 11:52

https://www.inflearn.com/course/%EC%9B%B9-mvc

 

스프링 웹 MVC - 인프런 | 강의

이 강좌는 자바 서블릿(Servlet) 기반의 MVC 프레임워크인 스프링 웹 MVC(이하 스프링 MVC)에 대해 학습합니다., 스프링 웹 MVC 이 강좌는 자바 서블릿(Servlet) 기반의 MVC 프레임워크인 스프링 웹 MVC(이하

www.inflearn.com

 

ㅁ 스프링 MVC 활용

ㅇ 요청 맵핑하기 - HTTP Method ,  URI 패턴 맵핑

- @GetMapping이 아닌 @RequestMapping으로 받으면 모든 method로 허용

 > method={} 형식으로 허용되는거 설정 가능

- 5번대 에러 서버 잘못

- 4번대 에러 요청이 잘못됨

- get은 post와 달리 캐싱을 할 수 있음, idempotent (멱등성)

- post는 put과 차이, put patch 차이

- 컨트롤러 위에 @RequestMapping을 달면 모든 핸들러에 해당 옵션 추가

 > get 요청 만 받기 등

- ** 하면 어떤 패스든 가능, * 하나면 한개의 패스만 가능

- 동일한 패스의 맵핑이 있으면, 코드 순서상 위에 있는것이 맵핑이 됨

- 핸들러 테스트도 가능 

                .andExpect(handler().handlerType(SampleController.class))
                .andExpect(handler().methodName("hello"))

- 스프링 MVC에서는 /hello로 맵핑할 경우, /hello.* 로 요청도 들어오게됨 (URI 확장자 맵핑 지원 )

 > 스프링 부트에서는 그렇지않음

 >> rfd (reflected file download attack) 방지를 위해 막아둠

- 여러 형식의 요청을 받아야할 경우 (파일 다운로드 등) - URI 확장자 맵핑은 하지않는게 좋음

1. content type 사용

2. parameter 사용

 

ㅇ 요청 맵핑하기 - 컨텐츠 타입 맵핑

- header에서 json 타입을 요청한 것만 받기 : @RequestMapping(value = "/hello", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE) ( 415 에러 - not Supported media type )

- produces = MediaType.TEXT_PLAIN_VALUE 로 요청하는 응답값을 보고 맵핑할 수도 있음 (406 에러 - not acceptable)

- consumes와 produces는 클래스에 선언한 @RequestMapping에 사용한 것과 조합되지 않고, 메소드에 사용한 RequestMapping의 설정으로 덮어쓴다.

ㅇ 요청 맵핑하기 - 헤더와 파라미터 맵핑

- headers = HttpHeaders.ACCEPT_LANGUAGE 로 헤더에 포함된 파라미터 요청만 매핑됨 ( ALLOW 헤더는 제외 )

 > not일 경우 : headers = "!" + HttpHeaders.FROM

 > 값이 일치 : headers = HttpHeaders.FROM + "=" + "localhost"

 > param 존재 및 값 일치 : params = "name=spring"

 

ㅇ 요청 맵핑하기 - HEAD와 OPTIONS 요청 처리

- 우리가 구현하지 않아도 스프링 웹 MVC에서 HTTP Method 로 HEAD와 OPTION을 설정함

- HEAD 요청은 GET과 비슷하나, response 의 body를 받지 않음

- OPTION 요청은 서버 또는 특정 리소스가 제공하는 기능을 확인할 수 있음 (METHOD 등)

 > controller가 응답하지는 않음

- hasItems, containsString 사용 (순서 맞게 하기 위해 )

                .andExpect(header().stringValues(HttpHeaders.ALLOW,
                        hasItems(
                                containsString("GET"),
                                containsString("POST"),
                                containsString("HEAD"),
                                containsString("OPTIONS")
                        )))

 

ㅇ 요청 맵핑하기 - 커스텀 애노테이션

- Composed Annotaion : 다른 애노테이션을 조합해서 만든것

- Meta Annotation : 애노테이션 위에 사용할 수 있는 에노테이션

- @Retention : 해당 애노테이션 정보를 언제까지 유지할 것인가

 > 자바의 애노테이션 : 기본값은 .class => 컴파일 후 런타임시 로드 후 사라지게됨 (로드할때)

                                   구동된 이후 유지하기 위해서는 런타임으로 설정 @Retention(RetentionPolicy.RUNTIME)                            

 

ㅇ 핸들러 메소드 - 아규먼트와 리턴 타입

- NativeWebRequest, WebRequest : 스프링이 제공하는거라 servlet api를 감싸는것

- Servlet시 구현한 HttpServletRequest , HttpServletResponse도 컨트롤러에서 파라미터로 가져올 수 있음

- pushbuilder : http2.0 리소스 푸쉬에 사용

- ResponseEntity: RESTAPI 응답으로 좋음

 

ㅇ 핸들러 메소드 - URI 패턴

- @PathVariable(required=false)

- Matrixvariable => WebConfig에 아래 구현

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }

ㅇ 핸들러 메소드 - 요청 매개변수 (단순 타입) & 폼 서브밋 & modelAttribute & Validated

- mockMvc는 파라미터로만 보낼 수 있음 (form은 어려움)

- @{} : URL 표현식

- ${} : variable 표현식

- *{} : selection 표현식 : scope 안에 특정 객체의 값을 선택해줌

- view(), model() 도 테스트 가능

                .andExpect(view().name("/events/form"))
                .andExpect(model().attributeExists("event"))

- RequestParam을 생략할수도 있음

- parameter로 보내는 값을 @ModelAttribute를 통해 바로 객체로 converting 할 수 있다.

 > binding 할때 type 에러가 발생할 수 있다.

 >> bindingResult 라는 변수로 따로 처리해줄 수 있음 (잘못된 입력값에 대한 처리 )

 - @Valid라는 애노테이션으로 값을 검증할 수 있음 (ex ) @Min(0) )

  > @Valid 는 그룹화하여 검증할 수 없음

  > @Validated는 그걸 보완함 (기초적인 기능은 동일 ) 

 

ㅇ 핸들러 메소드 - 폼 서브밋 에러 처리 & SessionAttributes & @SessionAttributes

- save 후 , redirect 로 조회 페이지로 보내기

 > refresh 해도 form 중복 submit을 안함\

 > Post -> redirect -> get 패턴

- HttpSession를 parameter로 사용해서 세션에 객체를 넣을 수도 있음

 > @SessionAttributes("event") 로 세션에 객체가 자동을 저장됨

 > 세션에 값을 왜 담을까? : 여러 화면에서 값을 입력해야할때가 있음, 이때 세션에 객체를 넣어서 다음에 계속 담아 submit함

 > 처리 후 sessionStatus.setComplete() 를 통해 비움

- @SessionAttributes 와 @SessionAttribute는 다른것임

 > SessionAttribute는 파라미터로 하나의 값을 가져옴

 > SessionAttributes는 위에 적었듯이 객체를 세션에 담음

- ModelAttribute 로 Session에 담긴 값도 객체 parameter로 받음

 

ㅇ 핸들러 메소드 - RedirectAttributes

- redirect 할때, model에 값을 담아주면 redirect url 뒤에 parameter로 넘어감

 > boot는 이 기능이 꺼져있음

 >> spring.mvc.ignore-default-model-on-redirect=false 로 켜야함

 >> 일부만 보내고 싶으면, redirectAttributes 사용

 >> redirect 되는곳에서 RequestParam으로 받아서 처리할 수 있다

- ModelAttribute로 parameter를 받을 수 있으나, session과 겹칠수도 잇기때문에, ModelAttirbute("new event") 와 같이 session 객체와 다르게 설정

- redirectAttributes 사용을 위해서는 모두 String parameter로 변해야함

 

ㅇ 핸들러 메소드 - Flash Attributes

- 데이터가 url에 노출되지 않는다.

- httpsession을 통해 전달됨

- model에 자동으로 들어가짐

- redirectAttributes에 addFlashAttributes 하여, 객체를 전달할 수 있음 (심지어 key, value(ojbect) 형식으로, 받는쪽에서 modelAttribute로 바로 받을수 있음

 

ㅇ 핸들러 메소드 - MultipartFile & 파일 다운로드

- 기본 디스페쳐 서블릿 전략은 multipart resolver가 없음

- 스프링 부트는 있음 

 > 우리가 설정하지 않더라도 파일을 업로드 할 수 있음

- @SpringBootTest는 모든 bean을 등록해주지만, MockMVC는 가져오지 않음

 > @AutoConfigureMockMvc로 가져와주자

- Response Entity를 만들어서 파일을 다운로드 하게 해줌

 > 헤더를 설정하고, 바디에 Resource로 파일 리소스를 가져와 넣어주면 됨

 > Response Entity로 만들어 리턴하면 응답이나 우리가 원하는걸 커스터마이징 할 수 있다.

- tika를 통해 헤더에 파일 타입을 자동으로 넣어줌

 

ㅇ 핸들러 메소드 - @RequestBody & HttpEntity

- 요청의 바디에 들어있는 데이터를 HttpMessageConverter를 통해 변환한 객체로 받는것

- @EnableWebMvc를 붙이는 순간, 

- 핸들러어댑터가 메시지 컨버터를 사용하며, 메소드 아규먼트를 resolve 함

 > 보통 헤더에 바디에 들어있는 데이터의 타입을 기입하여 들어옴

 > 이것을 참고하여 핸들러어댑터가 변환시켜줌

- ObjectMapper는 jackson이 제공하는건데, json <-> 스트링 변환 할 수있음

 > 자동 제공 및 빈으로 등록시켜줌

- HttpEntity<Event> 로 변환할 객체를 설정할 수 있다.

 > 헤더 정보를 확인할 수도 있다.

 >> HttpEntity<Event> request => request.getHeader().getContentType();

 > @RequestBody는 Body만 가져온다.

> extendMessageConverter를 통해 없는 converter는 추가

 

ㅇ 핸들러 메소드 - @ResponseBody & ResponseEntity

- @ResponseBody : 응답본문에 있는 메시지로 메소드의 return 타입을 담아줌 (httpMessageConverter 사용)

 > 기계한테는 json으로 보여주는게 유리, 사람한테는 html

- @RestController는 @ResponseBody 포함함

- ReponseEntity로 응답을 커스터마이징 할 수 있다.

 > 에러시 메시지 포함 등

 > ok(), badRequest().build() 등 자주쓰는건 이미 있음

 

ㅇ 모델 : @ModelAttribute 또 다른 사용법

- List.of는 자바 9 이상부터 가능

 - 모든 모델에 공통적인 값 설정 가능, 모델 정보 초기화

- @RequestMapping or @GetMapping과 같이 사용하면 해당 메소드에서 리턴하는 객체를 모델에 넣어준다.

    > RequestToViewNameTranslator가 요청 동일한 view로 리턴해준다.

 

ㅇ DataBinder : @InitBinder

- 아래와 같이 데이터 바인더 설정

        @InitBinder("Event")
        public void initEventBinder(WebDataBinder webDataBinder){
                // 아이디 필드를 데이터바인딩시 받지 않음
                webDataBinder.setDisallowedFields("id");
                // 유효값 검증을 위한 커스터마이징 validator 설정
                webDataBinder.addValidators(new EventValidator());
        }

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 로 LocalDate를 받을때 설정할 수 있다.

 

ㅇ 예외 처리 핸들러 @ExceptionHandler

- RuntimeException 을 상속할 경우, try catch 등이 필요없음

- 커스터마이징한 에러를 받아 모델에 담아 특정페이지로 return 할 수 있음

- ResponseEntity로 return 하여, 에러 메시지와 코드를 담아 리턴 함 (REST API 형식)

 

ㅇ 전역 컨트롤러 @ControllerAdvice

-  ExceptionHandler와 같이, 모든 컨트롤러에 공통적으로 처리하고 싶은값들을 설정함

- @ControllerAdvice(assignableTypes = {EventController.class, EventApi.class})

 와 같이 특정 컨트롤러에만 설정도 가능

- @RestControllerAdvice = @ControllerAdvice + @ResponseBody