New Score :0
High Score :0
Run Best
NICE BUSINESS TYPE INDICATOR
3. 급전을 친구에게 빌렸는데 오늘이 돈을 주기로 한날.. 그런데 카드값을 내야하는 날도 오늘인데... 이걸 어쩌나...
4. 우리 회사는 중요한 의사 결정을 할때?
5. 열심히 일한 나를 위한 선물을 주고싶다. 어떤게 좋을까?
6. 은행에서 투자상품을 추천받았다. 어떤걸 가입하지?
7. 회사에서의 나는?
8. 꿈에서 깨어나니 20년 전으로 돌아갔다. 당신이 제일 먼저 하는일은?
9. 내가 인사 담당자라면 신규 입사자 채용 시 제일 중요하게 보는것은?
10. 회사에 정말 싫어하는 동료가 있다면?
11. 가난한 집의 가장이 되었다.. 자녀의 생일 날 선물은?
12. 평소 회사 출근 스타일은?
13.회사 체육대회 하는 날이다. 오늘 뭐하지?
14. 나의 업무 스타일은?
1. Spring WebFlux
스프링 프레임 워크에 포함 된 원래 웹 프레임 워크 인 스프링 웹 MVC는 서블릿 API 및 서블릿 컨테이너 용으로 특별히 제작되었습니다. 반응형 스택 웹 프레임워크인 Spring WebFlux는 버전 5.0 후반에 추가되었습니다. 완전히 차단되지 않고 반응형 스트림 역 압력을 지원 하며 Netty, Undertow 및 서블릿 컨테이너와 같은 서버에서 실행됩니다.
두 웹 프레임 워크는 소스 모듈 (spring-webmvc 및 spring-webflux)의 이름을 미러링하고 Spring 프레임 워크에서 나란히 공존합니다. 각 모듈은 선택 사항입니다. 애플리케이션은 하나 또는 다른 모듈을 사용하거나 경우에 따라 둘 다 사용할 수 있습니다 (예 : 반응형 WebClient가있는 Spring MVC 컨트롤러).
1.1. Overview
Why was Spring WebFlux created?
해답의 일부는 적은 수의 스레드로 동시성을 처리하고 더 적은 하드웨어 리소스로 확장할 수 있는 비차단 웹 스택의 필요성입니다. 서블릿 비차단 I/O는 계약이 동기식(필터, 서블릿) 또는 차단(getParameter, getPart)인 서블릿 API의 나머지 부분에서 멀어집니다. 이것이 새로운 공통 API가 모든 비차단 런타임에서 기초 역할을 하게 된 동기였습니다. 이는 비동기, 비 차단 공간에 잘 설정된 서버 (예 : Netty) 때문에 중요합니다.
대답의 다른 부분은 함수형 프로그래밍입니다. Java 5에서 주석을 추가하면 기회(예: 주석이 추가된 REST 컨트롤러 또는 단위 테스트)가 생성됨과 마찬가지로 Java 8에 람다 표현식을 추가하면 Java에서 기능 API에 대한 기회가 생겼습니다. 이는 비동기 논리의 선언적 구성을 허용하는 비차단 애플리케이션 및 연속 스타일 API(CompletableFuture 및 ReactiveX에서 대중화됨)에 유용합니다. 프로그래밍 모델 수준에서 Java 8을 통해 Spring WebFlux는 주석이 달린 컨트롤러와 함께 기능적인 웹 엔드 포인트를 제공 할 수있었습니다.
1.1.1. Define “Reactive”
우리는 "비 차단"과 "기능적"에 대해 다루었지만 반응 성은 무엇을 의미합니까?
"반응형"이라는 용어는 I/O 이벤트에 반응하는 네트워크 구성 요소, 마우스 이벤트에 반응하는 UI 컨트롤러 등 변화에 반응하는 것을 중심으로 구축된 프로그래밍 모델을 의미합니다. 그런 의미에서 비차단은 차단되는 대신 이제 작업이 완료되거나 데이터를 사용할 수 있게 될 때 알림에 반응하는 모드에 있기 때문에 반응적입니다.
또한 Spring 팀에서 "반응성"과 연관시키는 또 다른 중요한 메커니즘이 있는데, 그것은 비 차단 배압입니다. 동기식 명령형 코드에서 호출 차단은 호출자가 대기하도록 하는 자연스러운 형태의 역 압력 역할을 합니다. 비차단 코드에서는 빠른 생산자가 대상을 압도하지 않도록 이벤트 속도를 제어하는 것이 중요합니다.
반응형 스트림은 비동기 구성 요소와 역 압력 간의 상호 작용을 정의하는 작은 사양 (Java 9에서도 채택 됨)입니다. 예를 들어 게시자 역할을 하는 데이터 리포지토리는 HTTP 서버(구독자 역할)가 응답에 쓸 수 있는 데이터를 생성할 수 있습니다. 반응형 스트림의 주요 목적은 구독자가 게시자가 데이터를 생성하는 속도 또는 속도를 제어할 수 있도록 하는 것입니다.
Common question: what if a publisher cannot slow down?
반응적 스트림의 목적은 메커니즘과 경계를 설정하는 것입니다. 게시자가 속도를 늦출 수 없는 경우 버퍼링, 삭제 또는 실패 여부를 결정해야 합니다.1.1.2. Reactive API
반응형 스트림은 상호 운용성에 중요한 역할을 합니다. 라이브러리 및 인프라 구성 요소에 관심이 있지만 너무 낮은 수준이기 때문에 응용 프로그램 API로는 덜 유용합니다. 애플리케이션은 비동기 로직을 작성하기 위해 더 높은 수준의 풍부한 기능의 API가 필요합니다 — Java 8 Stream API와 유사하지만 컬렉션에만 해당되는 것은 아닙니다. 이것이 반응형 라이브러리가 수행하는 역할입니다.
Reactor는 Spring WebFlux에 대해 선택되는 반응성 라이브러리입니다. 연산자의 ReactiveX 어휘와 일치하는 풍부한 연산자 집합을 통해 0..1(모노) 및 0..N(플럭스)의 데이터 시퀀스에서 작업할 수 있는 Mono 및 Flux API 유형을 제공합니다. Reactor는 반응성 스트림 라이브러리이므로 모든 작업자가 비차단 배압을 지원합니다. Reactor는 서버 측 Java에 중점을 둡니다. 그것은 Spring과의 긴밀한 협력을 통해 개발되었습니다.
WebFlux는 핵심 종속성으로 Reactor가 필요하지만 반응형 스트림을 통해 다른 반응형 라이브러리와 상호 운용할 수 있습니다. 일반적으로 WebFlux API는 일반 게시자를 입력으로 받아들이고, 내부적으로 Reactor 유형에 맞게 조정하고, 이를 사용하고, Flux 또는 Mono를 출력 으로 반환합니다.
따라서 모든 게시자를 입력으로 전달하고 출력에 작업을 적용할 수 있지만 다른 반응형 라이브러리와 함께 사용할 수 있도록 출력을 조정해야 합니다. 가능할 때마다(예: 주석이 달린 컨트롤러) WebFlux는 RxJava 또는 다른 반응형 라이브러리의 사용에 투명하게 적응합니다. 자세한 내용은 반응형 라이브러리를 참조하십시오.
반응형 API 외에도 WebFlux는 Kotlin의 코루틴 API와 함께 사용할 수 있어 보다 명령적인 프로그래밍 스타일을 제공합니다. 다음 Kotlin 코드 샘플은 코루틴 API와 함께 제공됩니다.
1.1.3. Programming Models
스프링 웹 모듈에는 HTTP 추상화, 지원되는 서버용 반응형 스트림 어댑터, 코덱 및 서블릿 API와 비슷하지만 비차단 계약이 있는 핵심 웹 핸들러 API를 포함하여 스프링 웹플럭스의 기초가 되는 반응형 기반이 포함되어 있습니다.
이를 바탕으로 Spring WebFlux는 두 가지 프로그래밍 모델 중 하나를 선택할 수 있습니다.
- Annotated Controllers: Spring MVC와 일치하며 스프링 웹 모듈의 동일한 주석을 기반으로합니다. Spring MVC 및 WebFlux 컨트롤러는 모두 반응 형 (Reactor 및 RxJava) 반환 유형을 지원하므로 결과적으로 구분하기가 쉽지 않습니다. 한 가지 주목할만한 차이점은 WebFlux가 반응형 @RequestBody 인수도 지원한다는 것입니다.
- Functional Endpoints: Lambda 기반, 경량 및 함수형 프로그래밍 모델. 이를 응용 프로그램이 요청을 라우팅하고 처리하는 데 사용할 수 있는 작은 라이브러리 또는 유틸리티 집합으로 생각할 수 있습니다. 주석이 달린 컨트롤러와의 가장 큰 차이점은 응용 프로그램이 처음부터 끝까지 요청 처리를 담당하고 주석을 통해 의도를 선언하고 콜백된다는 것입니다.
1.1.4. Applicability
Spring MVC or WebFlux?
자연스러운 질문이지만 불건전한 이분법을 설정하는 질문입니다. 실제로 둘 다 함께 작동하여 사용 가능한 옵션의 범위를 확장합니다. 이 둘은 서로의 연속성과 일관성을 위해 설계되었으며 나란히 사용할 수 있으며 각 측면의 피드백은 양측 모두에게 이익이됩니다. 다음 다이어그램에서는 두 가지가 어떻게 관련되어 있는지, 공통점이 무엇인지, 각각이 고유하게 지원하는 것을 보여 줍니다.
We suggest that you consider the following specific points:
- 잘 작동하는 Spring MVC 응용 프로그램이있는 경우 변경할 필요가 없습니다. 명령형 프로그래밍은 코드를 작성, 이해 및 디버그하는 가장 쉬운 방법입니다. 역사적으로 대부분이 차단되어 있기 때문에 라이브러리를 최대한 선택할 수 있습니다.
- 이미 비 차단 웹 스택을 구입하고있는 경우 Spring WebFlux는이 공간의 다른 웹 스택과 동일한 실행 모델 이점을 제공하며 서버 (Netty, Tomcat, Jetty, Undertow 및 Servlet 컨테이너), 프로그래밍 모델 선택 (주석이 달린 컨트롤러 및 기능 웹 엔드 포인트) 및 반응 형 라이브러리 선택 (Reactor, RxJava, 또는 기타).
- Java 8 람다 또는 Kotlin과 함께 사용할 수 있는 경량의 기능적 웹 프레임워크에 관심이 있는 경우 Spring WebFlux 기능 웹 엔드포인트를 사용할 수 있습니다. 또한 더 큰 투명성과 제어의 이점을 누릴 수 있는 덜 복잡한 요구 사항이 있는 소규모 애플리케이션 또는 마이크로 서비스에도 좋은 선택이 될 수 있습니다.
- 마이크로 서비스 아키텍처에서는 Spring MVC 또는 Spring WebFlux 컨트롤러 또는 Spring WebFlux 기능 엔드포인트를 사용하여 애플리케이션을 혼합할 수 있습니다. 두 프레임워크 모두에서 동일한 주석 기반 프로그래밍 모델을 지원하면 지식을 더 쉽게 재사용하는 동시에 올바른 작업에 적합한 도구를 선택할 수 있습니다.
- 응용 프로그램을 평가하는 간단한 방법은 종속성을 확인하는 것입니다. 사용할 차단 지속성 API (JPA, JDBC) 또는 네트워킹 API가있는 경우 Spring MVC는 적어도 일반적인 아키텍처에 가장 적합한 선택입니다. Reactor와 RxJava 모두에서 별도의 스레드에서 차단 호출을 수행하는 것은 기술적으로 가능하지만 비차단 웹 스택을 최대한 활용하지는 않습니다.
- 원격 서비스에 대한 호출이있는 Spring MVC 응용 프로그램이있는 경우 반응형 웹 클라이언트를 사용해보십시오. 반응 형 유형 (리액터, RxJava 또는 기타)을 Spring MVC 컨트롤러 메서드에서 직접 반환 할 수 있습니다. 통화당 대기 시간이 길거나 통화 간의 상호 종속성이 클수록 이점이 더 커집니다. Spring MVC 컨트롤러는 다른 반응 형 구성 요소도 호출 할 수 있습니다.
- 대규모 팀이 있는 경우 비차단, 기능 및 선언적 프로그래밍으로의 전환에서 가파른 학습 곡선을 염두에 두십시오. 전체 스위치 없이 시작하는 실용적인 방법은 반응형 WebClient를 사용하는 것입니다. 그 외에도 작게 시작하여 이점을 측정하십시오. 우리는 광범위한 응용 분야에서 이러한 변화가 불필요하다고 기대합니다. 어떤 이점을 찾아야 할지 잘 모르겠으면 먼저 비차단 I/O의 작동 방식(예: 단일 스레드 노드의 동시성.js 및 그 효과에 대해 알아봅니다.
1.1.5. Servers
Spring WebFlux는 Tomcat, Jetty, Servlet 컨테이너뿐만 아니라 Netty 및 Undertow와 같은 비 서블릿 런타임에서도 지원됩니다. 모든 서버는 낮은 수준의 공통 API에 맞게 조정되므로 서버 간에 상위 수준의 프로그래밍 모델을 지원할 수 있습니다.
스프링 WebFlux에는 서버를 시작하거나 중지하는 기본 제공 지원이 없습니다. 그러나 Spring 구성 및 WebFlux 인프라에서 응용 프로그램을 조립하고 몇 줄의 코드로 쉽게 실행할 수 있습니다.
스프링 부트에는 이러한 단계를 자동화하는 WebFlux 스타터가 있습니다. 기본적으로 스타터는 Netty를 사용하지만 Maven 또는 Gradle 종속성을 변경하여 Tomcat, Jetty 또는 Undertow로 쉽게 전환 할 수 있습니다. Spring Boot는 기본적으로 Netty로 설정되는데, 이는 비동기식, 비차단 공간에서 더 널리 사용되며 클라이언트와 서버가 리소스를 공유할 수 있도록 하기 때문입니다.
Tomcat과 Jetty는 Spring MVC 및 WebFlux와 함께 사용할 수 있습니다. 그러나 사용 방식은 매우 다릅니다. Spring MVC는 서블릿 차단 I / O에 의존하며 필요한 경우 응용 프로그램에서 서블릿 API를 직접 사용할 수 있습니다. 스프링 WebFlux는 서블릿 비 차단 I / O에 의존하며 저수준 어댑터 뒤에서 서블릿 API를 사용합니다. 직접 사용하기 위해 노출되지 않습니다.
Undertow의 경우 Spring WebFlux는 Servlet API없이 직접 Undertow API를 사용합니다.
1.1.6. Performance
성능에는 많은 특성과 의미가 있습니다. 반응형 및 비차단형은 일반적으로 응용 프로그램을 더 빠르게 실행하지 않습니다. 경우에 따라 원격 호출을 병렬로 실행하는 경우와 같이 수행할 수 있습니다. 전반적으로 비 차단 방식으로 작업을 수행하려면 더 많은 작업이 필요하며 필요한 처리 시간이 약간 늘어날 수 있습니다.
반응적 및 비차단의 주요 예상 이점은 작고 고정된 수의 스레드와 더 적은 메모리로 확장할 수 있다는 것입니다. 이렇게 하면 응용 프로그램이 더 예측 가능한 방식으로 확장되기 때문에 부하 상태에서 응용 프로그램의 복원력이 향상됩니다. 그러나 이러한 이점을 관찰하려면 약간의 대기 시간(느리고 예측할 수 없는 네트워크 I/O의 혼합 포함)이 필요합니다. 이것이 반응 스택이 강점을 보여주기 시작하는 곳이며 그 차이는 극적 일 수 있습니다.
1.1.7. Concurrency Model
Spring MVC 및 Spring WebFlux는 모두 주석이 달린 컨트롤러를 지원하지만 동시성 모델과 차단 및 스레드에 대한 기본 가정에는 중요한 차이점이 있습니다.
Spring MVC (및 일반적으로 서블릿 응용 프로그램)에서는 응용 프로그램이 현재 스레드를 차단할 수 있다고 가정합니다 (예 : 원격 호출). 이러한 이유로 서블릿 컨테이너는 대형 스레드 풀을 사용하여 요청 처리 중에 잠재적 차단을 흡수합니다.
Spring WebFlux (및 일반적으로 비 차단 서버)에서는 응용 프로그램이 차단되지 않는다고 가정합니다. 따라서 비차단 서버는 작은 고정 크기 스레드 풀(이벤트 루프 작업자)을 사용하여 요청을 처리합니다.
"확장하기"와 "적은 수의 스레드"는 모순적으로 들릴 수 있지만 현재 스레드를 차단하지 않고 대신 콜백에 의존한다는 것은 흡수 할 차단 호출이 없으므로 추가 스레드가 필요하지 않다는 것을 의미합니다.
Invoking a Blocking API
차단 라이브러리를 사용해야 하는 경우 어떻게 해야 합니까? Reactor와 RxJava는 모두 다른 스레드에서 처리를 계속할 수 있도록 publishOn 연산자를 제공합니다. 즉, 쉬운 탈출 해치가 있습니다. 그러나 API 차단은 이 동시성 모델에 적합하지 않습니다.
Mutable State
Reactor 및 RxJava에서는 연산자를 통해 논리를 선언합니다. 런타임에 데이터가 별개의 단계에서 순차적으로 처리되는 반응형 파이프라인이 형성됩니다. 이것의 주요 이점은 해당 파이프라인 내의 응용 프로그램 코드가 동시에 호출되지 않기 때문에 응용 프로그램이 변경 가능한 상태를 보호할 필요가 없다는 것입니다.
Threading Model
Spring WebFlux로 실행되는 서버에서 어떤 스레드를 볼 수 있습니까?
- "바닐라"Spring WebFlux 서버 (예 : 데이터 액세스 또는 기타 선택적 종속성 없음)에서 서버에 대해 하나의 스레드를 예상하고 요청 처리를 위해 다른 여러 스레드 (일반적으로 CPU 코어 수만큼)를 기대할 수 있습니다. 그러나 서블릿 컨테이너는 서블릿(차단) I/O 및 서블릿 10.3(비차단) I/O 사용을 모두 지원하기 위해 더 많은 스레드(예: Tomcat의 경우 1개)로 시작할 수 있습니다.
- 반응형 WebClient는 이벤트 루프 스타일로 작동합니다. 따라서 이와 관련된 작고 고정된 수의 처리 스레드를 볼 수 있습니다(예: Reactor Netty 커넥터가 있는 reactor-http-nio-). 그러나 Reactor Netty가 클라이언트와 서버 모두에 사용되는 경우 두 개는 기본적으로 이벤트 루프 리소스를 공유합니다.
- Reactor 및 RxJava는 처리를 다른 스레드 풀로 전환하는 데 사용되는 publishOn 연산자와 함께 사용할 스케줄러라는 스레드 풀 추상화를 제공합니다. 스케줄러에는 특정 동시성 전략을 제안하는 이름(예: "병렬"(스레드 수가 제한된 CPU 바인딩 작업의 경우) 또는 "탄력적"(스레드 수가 많은 I/O 바인딩된 작업의 경우)이 있습니다. 이러한 스레드가 표시되면 일부 코드가 특정 스레드 풀 스케줄러 전략을 사용하고 있음을 의미합니다.
- 데이터 액세스 라이브러리 및 기타 타사 종속성도 자체 스레드를 만들고 사용할 수 있습니다.
1.2. Reactive Core
spring-web 모듈에는 반응형 웹 응용 프로그램에 대한 다음과 같은 기본 지원이 포함되어 있습니다.
- 서버 요청 처리에는 두 가지 수준의 지원이 있습니다.
- HttpHandler: 비차단 I/O 및 반응성 스트림 배압을 사용한 HTTP 요청 처리에 대한 기본 계약과 Reactor Netty, Undertow, Tomcat, Jetty 및 모든 서블릿 컨테이너용 어댑터.
- WebHandler API: 요청 처리를 위한 약간 더 높은 수준의 범용 웹 API로, 그 위에 주석이 추가된 컨트롤러 및 기능 끝점과 같은 구체적인 프로그래밍 모델이 빌드됩니다.
- 클라이언트 측의 경우 Reactor Netty, Reactive Jetty HttpClient 및 Apache HttpComponents용 어댑터와 함께 비차단 I/O 및 반응형 스트림 역 압력으로 HTTP 요청을 수행하는 기본 ClientHttpConnector 계약이 있습니다. 응용 프로그램에 사용되는 상위 수준 WebClient는 이 기본 계약을 기반으로 합니다.
- 클라이언트 및 서버의 경우 HTTP 요청 및 응답 콘텐츠의 직렬화 및 역직렬화를 위한 코덱입니다.
1.2.1. HttpHandler
HttpHandler는 요청 및 응답을 처리하는 단일 메서드가 있는 간단한 계약입니다. 의도적으로 최소한이며, 주요 목적은 다른 HTTP 서버 API에 대한 최소한의 추상화입니다.
다음 표에서는 지원되는 서버 API에 대해 설명합니다.
Netty | Netty API | Reactor Netty |
Undertow | Undertow API | spring-web: Undertow to Reactive Streams bridge |
Tomcat | Servlet non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[] | spring-web: Servlet non-blocking I/O to Reactive Streams bridge |
Jetty | Servlet non-blocking I/O; Jetty API to write ByteBuffers vs byte[] | spring-web: Servlet non-blocking I/O to Reactive Streams bridge |
Servlet container | Servlet non-blocking I/O | spring-web: Servlet non-blocking I/O to Reactive Streams bridge |
다음 표에서는 서버 종속성에 대해 설명합니다(지원되는 버전도 참조).
Server name | Group id | Artifact name |
Reactor Netty | io.projectreactor.netty | reactor-netty |
Undertow | io.undertow | undertow-core |
Tomcat | org.apache.tomcat.embed | tomcat-embed-core |
Jetty | org.eclipse.jetty | jetty-server, jetty-servlet |
아래 코드 조각은 각 서버 API에서 HttpHandler 어댑터를 사용하는 방법을 보여 줍니다.
val handler: HttpHandler = ...
val adapter = ReactorHttpHandlerAdapter(handler)
HttpServer.create().host(host).port(port).handle(adapter).bindNow()
Undertow
val handler: HttpHandler = ...
val adapter = UndertowHttpHandlerAdapter(handler)
val server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build()
server.start()
Tomcat
val handler: HttpHandler = ...
val servlet = TomcatHttpHandlerAdapter(handler)
val server = Tomcat()
val base = File(System.getProperty("java.io.tmpdir"))
val rootContext = server.addContext("", base.absolutePath)
Tomcat.addServlet(rootContext, "main", servlet)
rootContext.addServletMappingDecoded("/", "main")
server.host = host
server.setPort(port)
server.start()
Jetty
val handler: HttpHandler = ...
val servlet = JettyHttpHandlerAdapter(handler)
val server = Server()
val contextHandler = ServletContextHandler(server, "")
contextHandler.addServlet(ServletHolder(servlet), "/")
contextHandler.start();
val connector = ServerConnector(server)
connector.host = host
connector.port = port
server.addConnector(connector)
server.start()
Servlet Container
서블릿 컨테이너에 WAR로 배포하려면 WAR에서 AbstractReactiveWebInitializer를 확장하고 포함할 수 있습니다. 이 클래스는 ServletHttpHandlerAdapter로 HttpHandler를 래핑하고 서블릿으로 등록합니다.
1.2.2. WebHandler API
org.springframework.web.server 패키지는 HttpHandler 계약을 기반으로 여러 WebExceptionHandler, 여러 WebFilter 및 단일 WebHandler 구성 요소의 체인을 통해 요청을 처리하기 위한 범용 웹 API를 제공합니다. 체인은 구성 요소가 자동 감지되는 Spring ApplicationContext를 가리키거나 빌더에 구성 요소를 등록하여 WebHttpHandlerBuilder와 함께 넣을 수 있습니다.
HttpHandler는 다양한 HTTP 서버의 사용을 추상화하는 간단한 목표를 가지고 있지만 WebHandler API는 다음과 같은 웹 응용 프로그램에서 일반적으로 사용되는 광범위한 기능 집합을 제공하는 것을 목표로 합니다.
- User session with attributes.
- Request attributes.
- Resolved Locale or Principal for the request.
- Access to parsed and cached form data.
- Abstractions for multipart data.
- and more..
Special bean types
아래 표에는 WebHttpHandlerBuilder가 Spring ApplicationContext에서 자동 감지할 수 있거나 직접 등록할 수 있는 구성 요소가 나열되어 있습니다.
Bean name | Bean type | Count | Description |
<any> | WebExceptionHandler | 0..N | WebFilter 인스턴스 체인과 대상 웹 처리기의 예외를 처리합니다. 자세한 내용은 예외를 참조하십시오. |
<any> | WebFilter | 0..N | 가로채기 스타일 논리를 필터 체인의 나머지 부분과 대상 WebHandler 앞뒤에 적용합니다. 자세한 내용은 필터를 참조하십시오. |
webHandler | WebHandler | 1 | 요청에 대한 처리기입니다. |
webSessionManager | WebSessionManager | 0..1 | ServerWebExchange의 메서드를 통해 노출되는 WebSession 인스턴스의 관리자입니다. 기본적으로 DefaultWebSessionManager입니다. |
serverCodecConfigurer | ServerCodecConfigurer | 0..1 | 양식 데이터 및 다중 파트 데이터를 구문 분석하기 위해 HttpMessageReader 인스턴스에 액세스한 다음 ServerWebExchange의 메서드를 통해 노출됩니다. ServerCodecConfigurer.create() 기본적으로. |
localeContextResolver | LocaleContextResolver | 0..1 | ServerWebExchange의 메서드를 통해 노출되는 LocaleContext에 대한 확인자입니다. 기본적으로 AcceptHeaderLocaleContextResolver입니다. |
forwardedHeaderTransformer | ForwardedHeaderTransformer | 0..1 | 전달된 형식 헤더를 추출하여 제거하거나 제거만 하여 처리합니다. 기본적으로 사용되지 않습니다. |
Form Data
ServerWebExchange exposes the following method for accessing form data:
suspend fun getFormData(): MultiValueMap<String, String>
DefaultServerWebExchange는 구성된 HttpMessageReader를 사용하여 양식 데이터(application/x-www-form-urlencoded)를 MultiValueMap으로 구문 분석합니다. 기본적으로, FormHttpMessageReader는 ServerCodecConfigurer Bean에서 사용하도록 구성됩니다(웹 핸들러 API 참조).
Multipart Data
ServerWebExchange exposes the following method for accessing multipart data:
suspend fun getMultipartData(): MultiValueMap<String, Part>
DefaultServerWebExchange는 구성된 HttpMessageReader<MultiValueMap<String, Part>>를 사용하여 multipart/form data, multipart/mixed 및 multipart/related 콘텐츠를 MultiValueMap으로 구문 분석합니다. 기본적으로 이 메서드는 타사 종속성이 없는 DefaultPartHttpMessageReader입니다. 또는 Synchronosss NIO Multipart 라이브러리를 기반으로 하는 SynchronossPartHttpMessageReader를 사용할 수 있습니다. 둘 다 ServerCodecConfigurer Bean을 통해 구성됩니다(웹 핸들러 API 참조).
스트리밍 방식으로 멀티파트 데이터를 구문 분석하려면 @RequestPart 대신 PartEventHttpMessageReader에서 반환된 Flux<PartEvent>를 사용할 수 있는데, 이는 이름별로 개별 파트에 대한 맵과 같은 액세스를 의미하므로 멀티파트 데이터 전체를 구문 분석해야 합니다. 반면, @RequestBody 사용하면 MultiValueMap에 수집하지 않고 Flux<PartEvent>로 콘텐츠를 디코딩할 수 있습니다.
Forwarded Headers
요청이 프록시(예: 부하 분산 장치)를 통과하면 호스트, 포트 및 체계가 변경될 수 있습니다. 따라서 클라이언트 관점에서 올바른 호스트, 포트 및 체계를 가리키는 링크를 만드는 것이 어렵습니다.
RFC 7239는 프록시가 원래 요청에 대한 정보를 제공하는 데 사용할 수 있는 전달된 HTTP 헤더를 정의합니다. X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-SSL 및 X-Forwarded-Prefix를 포함한 다른 비표준 헤더도 있습니다.
ForwardedHeaderTransformer는 전달된 헤더를 기반으로 요청의 호스트, 포트 및 체계를 수정한 다음 해당 헤더를 제거하는 구성 요소입니다. forwardedHeaderTransformer 라는 이름을 가진 Bean으로 선언하면 감지되어 사용됩니다.
전달된 헤더에 대한 보안 고려 사항이 있는데, 이는 응용 프로그램이 헤더가 의도한 대로 프록시에 의해 추가되었는지 또는 악의적인 클라이언트에 의해 추가되었는지 알 수 없기 때문입니다. 따라서 외부에서 들어오는 신뢰할 수 없는 전달된 트래픽을 제거하도록 신뢰 경계의 프록시를 구성해야 합니다. removeOnly=true를 사용하여 ForwardedHeaderTransformer를 구성할 수도 있는데, 이 경우 헤더는 제거되지만 헤더는 사용되지 않습니다.
5.1에서 ForwardedHeaderFilter는 더 이상 사용되지 않고 ForwardedHeaderTransformer로 대체되었으므로 교환이 생성되기 전에 전달된 헤더를 더 일찍 처리할 수 있습니다. 그래도 필터가 구성되어 있으면 필터 목록에서 제거되고 대신 ForwardedHeaderTransformer가 사용됩니다.
1.2.3. Filters
웹 처리기 API에서 WebFilter를 사용하여 필터의 나머지 처리 체인과 대상 웹 처리기 앞뒤에 가로채기 스타일 논리를 적용할 수 있습니다. WebFlux 구성을 사용할 때 WebFilter를 등록하는 것은 스프링 빈으로 선언하고 (선택적으로) 빈 선언에 @Order 사용하거나 Ordered를 구현하여 우선 순위를 표현하는 것만 큼 간단합니다.
CORS
스프링 WebFlux는 컨트롤러의 주석을 통해 CORS 구성에 대한 세분화된 지원을 제공합니다. 그러나 스프링 보안과 함께 사용할 때는 스프링 보안의 필터 체인보다 먼저 주문해야하는 내장 CorsFilter에 의존하는 것이 좋습니다.
자세한 내용은 CORS 및 CORS 웹 필터 섹션을 참조하세요.
1.2.4. Exceptions
웹 처리기 API에서 WebExceptionHandler를 사용하여 WebFilter 인스턴스 및 대상 웹 처리기 체인의 예외를 처리할 수 있습니다. WebFlux Config를 사용할 때 WebExceptionHandler를 등록하는 것은 스프링 빈으로 선언하고 (선택적으로) Bean 선언에 @Order 사용하거나 Ordered를 구현하여 우선 순위를 표현하는 것만 큼 간단합니다.
The following table describes the available WebExceptionHandler implementations:
Exception Handler | Description |
ResponseStatusExceptionHandler | 예외의 HTTP 상태 코드에 대한 응답을 설정하여 ResponseStatusException 형식의 예외를 처리합니다. |
WebFluxResponseStatusExceptionHandler | 예외에 대한 @ResponseStatus 주석의 HTTP 상태 코드도 확인할 수 있는 ResponseStatusExceptionHandler의 확장입니다. 이 핸들러는 WebFlux 구성에서 선언됩니다. |
1.2.5. Codecs
스프링 웹 및 스프링 코어 모듈은 Reactive Streams 역 압력이 있는 비차단 I/O를 통해 상위 수준 개체와 바이트 콘텐츠를 직렬화 및 역직렬화할 수 있도록 지원합니다. 다음은 이 지원에 대한 설명입니다.
- 인코더 및 디코더는 HTTP와 독립적으로 콘텐츠를 인코딩 및 디코딩하는 하위 수준 계약입니다.
- HttpMessageReader 및 HttpMessageWriter는 HTTP 메시지 콘텐츠를 인코딩 및 디코딩하기 위한 계약입니다.
- 인코더는 EncoderHttpMessageWriter로 래핑하여 웹 애플리케이션에서 사용할 수 있도록 조정할 수 있으며, 디코더는 DecoderHttpMessageReader로 래핑할 수 있습니다.
- DataBuffer는 다양한 바이트 버퍼 표현 (예 : Netty ByteBuf, java.nio.ByteBuffer 등)을 추상화하며 모든 코덱이 작동하는 것입니다. 이 주제에 대한 자세한 내용은 "Spring Core"섹션의 데이터 버퍼 및 코덱을 참조하십시오.
스프링 코어 모듈은 byte[], ByteBuffer, DataBuffer, 리소스 및 문자열 인코더 및 디코더 구현을 제공합니다. 스프링 웹 모듈은 양식 데이터, 멀티파트 콘텐츠, 서버 전송 이벤트 등에 대한 웹 전용 HTTP 메시지 판독기 및 작성기 구현과 함께 Jackson JSON, Jackson Smile, JAXB2, 프로토콜 버퍼 및 기타 인코더 및 디코더를 제공합니다.
및 ServerCodecConfigurer는 일반적으로 응용 프로그램에서 사용할 코덱을 구성하고 사용자 지정하는 데 사용됩니다. HTTP 메시지 코덱 구성에 대한 섹션을 참조하십시오.
Jackson JSON
JSON and binary JSON (Smile) Jackson 라이브러리가 있을 때 둘 다 지원됩니다.
The Jackson2Decoder works as follows:
- 잭슨의 비동기식, 비차단 파서는 바이트 청크 스트림을 각각 JSON 객체를 나타내는 TokenBuffer로 집계하는 데 사용됩니다.
- 각 TokenBuffer는 잭슨의 ObjectMapper에 전달되어 더 높은 수준의 객체를 만듭니다.
- 단일 값 게시자(예: Mono)로 디코딩할 때 하나의 TokenBuffer가 있습니다.
- 다중 값 게시자(예: Flux)로 디코딩할 때 각 TokenBuffer는 완전히 형성된 개체에 대해 충분한 바이트가 수신되는 즉시 ObjectMapper에 전달됩니다. 입력 콘텐츠는 JSON 배열이거나 줄로 구분된 JSON 형식(예: NDJSON, JSON 줄 또는 JSON 텍스트 시퀀스)일 수 있습니다.
The Jackson2Encoder works as follows:
- 단일 값 게시자(예: Mono)의 경우 ObjectMapper를 통해 직렬화하기만 하면 됩니다.
- application/json이 있는 다중 값 게시자의 경우 기본적으로 Flux#collectToList()를 사용하여 값을 수집한 다음 결과 컬렉션을 직렬화합니다.
- 애플리케이션/x-ndjson 또는 애플리케이션/스트림+x-잭슨-스마일과 같은 스트리밍 미디어 유형을 사용하는 다중값 게시자의 경우 줄로 구분된 JSON 형식을 사용하여 각 값을 개별적으로 인코딩, 쓰기 및 플러시합니다. 다른 스트리밍 미디어 유형이 인코더에 등록될 수 있습니다.
- SSE의 경우 Jackson2Encoder가 이벤트별로 호출되고 지연없이 전달되도록 출력이 플러시됩니다.
기본적으로 Jackson2Encoder와 Jackson2Decoder는 모두 문자열 형식의 요소를 지원하지 않습니다. 대신 기본 가정은 문자열 또는 문자열 시퀀스가 CharSequenceEncoder에 의해 렌더링될 직렬화된 JSON 콘텐츠를 나타내는 것입니다. 필요한 것이 Flux<String>에서 JSON 배열을 렌더링하는 것이라면 Flux#collectToList()를 사용하고 Mono<List<String>>을 인코딩합니다.
Form Data
FormHttpMessageReader 및 FormHttpMessageWriter는 디코딩 및 인코딩 응용 프로그램/x-www-form-urlencoded 콘텐츠를 지원합니다.
양식 콘텐츠에 여러 위치에서 액세스해야 하는 경우가 많은 서버 쪽에서 ServerWebExchange는 FormHttpMessageReader를 통해 콘텐츠를 구문 분석한 다음 반복적인 액세스를 위해 결과를 캐시하는 전용 getFormData() 메서드를 제공합니다. 웹 처리기 API 섹션의 양식 데이터를 참조하십시오.
getFormData()를 사용하면 요청 본문에서 원본 원시 콘텐츠를 더 이상 읽을 수 없습니다. 이러한 이유로 응용 프로그램은 원시 요청 본문에서 읽는 대신 캐시된 양식 데이터에 액세스하기 위해 일관되게 ServerWebExchange를 거쳐야 합니다.
Multipart
및 MultipartHttpMessageWriter는 "multipart/form-data", "multipart/mixed" 및 "multipart/related" 콘텐츠의 디코딩 및 인코딩을 지원합니다. 그러면 MultipartHttpMessageReader는 Flux<Part>에 대한 실제 구문 분석을 위해 다른 HttpMessageReader에 위임한 다음 단순히 파트를 MultiValueMap으로 수집합니다. 기본적으로 DefaultPartHttpMessageReader가 사용되지만 ServerCodecConfigurer를 통해 변경할 수 있습니다. DefaultPartHttpMessageReader에 대한 자세한 내용은 DefaultPartHttpMessageReader의 javadoc을 참조하십시오.
여러 위치에서 다중 파트 양식 콘텐츠에 액세스해야 할 수 있는 서버 쪽에서 ServerWebExchange는 MultipartHttpMessageReader를 통해 콘텐츠를 구문 분석한 다음 반복 액세스를 위해 결과를 캐시하는 전용 getMultipartData() 메서드를 제공합니다. 웹 처리기 API 섹션의 다중 파트 데이터를 참조하세요.
getMultipartData()를 사용하면 요청 본문에서 원본 원시 콘텐츠를 더 이상 읽을 수 없습니다. 이러한 이유로 애플리케이션은 파트에 대한 반복적인 맵 유사 액세스를 위해 getMultipartData()를 일관되게 사용하거나 Flux<Part>에 대한 일회성 액세스를 위해 SynchronossPartHttpMessageReader에 의존해야 합니다.
Limits
입력 스트림의 일부 또는 전부를 버퍼링하는 디코더 및 HttpMessageReader 구현은 메모리에 버퍼링할 최대 바이트 수에 대한 제한을 사용하여 구성할 수 있습니다. 경우에 따라 입력이 집계되고 단일 개체(예: @RequestBody바이트[], x-www-form-url인코딩된 데이터가 있는 컨트롤러 메서드)로 표현되기 때문에 버퍼링이 발생합니다. 버퍼링은 입력 스트림(예: 구분된 텍스트, JSON 개체의 스트림 등)을 분할할 때 스트리밍에서도 발생할 수 있습니다. 이러한 스트리밍의 경우 제한은 스트림의 한 개체와 연결된 바이트 수에 적용됩니다.
버퍼 크기를 구성하려면 주어진 디코더 또는 HttpMessageReader가 maxInMemorySize 속성을 노출하는지 확인하고 그렇다면 Javadoc에 기본값에 대한 세부 정보가 있는지 확인할 수 있습니다. 서버 쪽에서 ServerCodecConfigurer는 모든 코덱을 설정할 수 있는 단일 위치를 제공합니다(HTTP 메시지 코덱 참조). 클라이언트 측에서는 WebClient.Builder에서 모든 코덱에 대한 제한을 변경할 수 있습니다.
다중 파트 구문 분석의 경우 maxInMemorySize 속성은 파일이 아닌 파트의 크기를 제한합니다. 파일 파트의 경우 파트가 디스크에 기록되는 임계값을 결정합니다. 디스크에 기록된 파일 파트의 경우 파트당 디스크 공간을 제한하는 추가 maxDiskUsagePerPart 속성이 있습니다. 다중 파트 요청에서 전체 파트 수를 제한하는 maxParts 속성도 있습니다. WebFlux에서 세 가지를 모두 구성하려면 MultipartHttpMessageReader의 미리 구성된 인스턴스를 ServerCodecConfigurer에 제공해야 합니다.
Streaming
HTTP 응답(예: 텍스트/이벤트 스트림, application/x-ndjson)으로 스트리밍할 때 연결이 끊긴 클라이언트를 조만간 안정적으로 감지하려면 주기적으로 데이터를 보내는 것이 중요합니다. 이러한 전송은 주석 전용, 빈 SSE 이벤트 또는 하트비트 역할을 효과적으로 수행할 수 있는 기타 "작동 금지" 데이터일 수 있습니다.
DataBuffer
DataBuffer는 WebFlux의 바이트 버퍼에 대한 표현입니다. 이 참조의 Spring Core 부분에는 데이터 버퍼 및 코덱 섹션에서 자세히 설명합니다. 이해해야 할 요점은 Netty와 같은 일부 서버에서는 바이트 버퍼가 풀링되고 참조 횟수가 계산되며 메모리 누수를 방지하기 위해 소비 될 때 해제되어야한다는 것입니다.
WebFlux 애플리케이션은 일반적으로 코덱을 사용하여 상위 수준 개체로 변환하거나 사용자 지정 코덱을 만들지 않는 한 데이터 버퍼를 직접 사용하거나 생성하지 않는 한 이러한 문제에 관심을 가질 필요가 없습니다. 이러한 경우 데이터 버퍼 및 코덱의 정보, 특히 DataBuffer 사용 섹션을 검토하십시오.
1.2.6. Logging
스프링 WebFlux의 디버그 레벨 로깅은 작고 최소이며 인간 친화적으로 설계되었습니다. 반복해서 유용한 정보의 높은 가치와 특정 문제를 디버깅 할 때만 유용한 정보에 중점을 둡니다.
TRACE 레벨 로깅은 일반적으로 DEBUG와 동일한 원칙을 따르지만(예를 들어 파이어호스가 아니어야 함) 모든 문제를 디버깅하는 데 사용할 수 있습니다. 또한 일부 로그 메시지는 TRACE 및 DEBUG에서 다른 수준의 세부 정보를 표시할 수 있습니다.
좋은 로깅은 로그 사용 경험에서 비롯됩니다. 명시된 목표를 충족하지 못하는 것을 발견하면 알려주십시오.
Log Id
WebFlux에서는 단일 요청을 여러 스레드에서 실행할 수 있으며 스레드 ID는 특정 요청에 속하는 로그 메시지의 상관 관계를 지정하는 데 유용하지 않습니다. 이것이 WebFlux 로그 메시지에 기본적으로 요청별 ID가 접두사로 붙는 이유입니다.
서버 측에서 로그 ID는 ServerWebExchange 특성(LOG_ID_ATTRIBUTE)에 저장되지만 해당 ID를 기반으로 하는 완전한 형식의 접두사는 ServerWebExchange#getLogPrefix()에서 사용할 수 있습니다. WebClient 측에서 로그 ID는 ClientRequest 속성(LOG_ID_ATTRIBUTE)에 저장되지만 완전한 형식의 접두사는 ClientRequest#logPrefix()에서 사용할 수 있습니다.
Sensitive Data
디버그 및 추적 로깅은 중요한 정보를 기록할 수 있습니다. 이것이 양식 매개 변수와 헤더가 기본적으로 마스킹되는 이유이며 전체 로깅을 명시적으로 활성화해야 합니다.
다음 예제에서는 서버 쪽 요청에 대해 이 작업을 수행하는 방법을 보여 줍니다.
@Configuration
@EnableWebFlux
class MyConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().enableLoggingRequestDetails(true)
}
}
다음 예제에서는 클라이언트 쪽 요청에 대해 이 작업을 수행하는 방법을 보여 줍니다.
val consumer: (ClientCodecConfigurer) -> Unit = { configurer -> configurer.defaultCodecs().enableLoggingRequestDetails(true) }
val webClient = WebClient.builder()
.exchangeStrategies({ strategies -> strategies.codecs(consumer) })
.build()
Appenders
SLF4J 및 Log4J 2와 같은 로깅 라이브러리는 차단을 방지하는 비동기 로거를 제공합니다. 로깅을 위해 큐에 대기할 수 없는 메시지를 잠재적으로 삭제하는 것과 같은 고유한 단점이 있지만 현재 사후 대응적이고 비차단 응용 프로그램에서 사용할 수 있는 최상의 옵션입니다.
Custom codecs
응용 프로그램은 추가 미디어 유형 또는 기본 코덱에서 지원하지 않는 특정 동작을 지원하기 위해 사용자 지정 코덱을 등록할 수 있습니다.
개발자가 표현한 일부 구성 옵션은 기본 코덱에 적용됩니다. 사용자 지정 코덱은 버퍼링 제한 적용 또는 중요한 데이터 로깅과 같은 기본 설정에 맞출 기회를 원할 수 있습니다.
다음 예제에서는 클라이언트 쪽 요청에 대해 이 작업을 수행하는 방법을 보여 줍니다.
val webClient = WebClient.builder()
.codecs({ configurer ->
val decoder = CustomDecoder()
configurer.customCodecs().registerWithDefaultConfig(decoder)
})
.build()
1.3. DispatcherHandler
Spring MVC와 유사하게 Spring WebFlux는 중앙 웹 핸들러 인 DispatcherHandler가 요청 처리를위한 공유 알고리즘을 제공하는 반면 실제 작업은 구성 가능한 대리자 구성 요소에 의해 수행되는 전면 컨트롤러 패턴을 중심으로 설계되었습니다. 이 모델은 유연하며 다양한 워크플로를 지원합니다.
디스패처 핸들러는 스프링 구성에서 필요한 대리자 구성 요소를 검색합니다. 또한 스프링 빈 자체로 설계되었으며 실행되는 컨텍스트에 액세스하기 위해 ApplicationContextAware를 구현합니다. DispatcherHandler가 webHandler의 Bean 이름으로 선언되면, WebHandler API에 설명된 대로 요청 처리 체인을 조합하는 WebHttpHandlerBuilder에 의해 차례로 발견됩니다.
WebFlux 애플리케이션의 스프링 구성에는 일반적으로 다음이 포함됩니다.
- Bean 이름을 가진 DispatcherHandler webHandler
- WebFilter and WebExceptionHandler beans
- DispatcherHandler special beans
- Others
다음 예제와 같이 처리 체인을 빌드하기 위해 WebHttpHandlerBuilder에 구성이 제공됩니다.
val context: ApplicationContext = ...
val handler = WebHttpHandlerBuilder.applicationContext(context).build()
결과 HttpHandler는 서버 어댑터와 함께 사용할 준비가 되었습니다.
1.3.1. Special Bean Types
디스패처핸들러는 요청을 처리하고 적절한 응답을 렌더링하기 위해 특수 Bean에 위임합니다. "특수 빈"이란 WebFlux 프레임 워크 계약을 구현하는 스프링 관리 개체 인스턴스를 의미합니다. 일반적으로 기본 제공 계약과 함께 제공되지만 속성을 사용자 지정하거나 확장하거나 바꿀 수 있습니다.
다음 표에는 디스패처 핸들러에서 발견한 특수 Bean이 나열되어 있습니다. 하위 레벨에서 발견된 다른 Bean도 있습니다(웹 핸들러 API의 특수 Bean 유형 참조).
Bean type | Explanation |
HandlerMapping | 요청을 처리기에 매핑합니다. 매핑은 몇 가지 기준을 기반으로 하며, 세부 정보는 HandlerMapping 구현(주석이 달린 컨트롤러, 단순 URL 패턴 매핑 등)에 따라 다릅니다. 주요 HandlerMapping 구현은 @RequestMapping 주석이 추가된 메서드에 대한 RequestMappingHandlerMapping, 기능적 끝점 경로에 대한 RouterFunctionMapping, URI 경로 패턴 및 WebHandler 인스턴스의 명시적 등록을 위한 SimpleUrlHandlerMapping입니다. |
HandlerAdapter | DispatcherHandler가 처리기가 실제로 호출되는 방식에 관계없이 요청에 매핑된 처리기를 호출하도록 도와줍니다. 예를 들어 주석이 추가된 컨트롤러를 호출하려면 주석을 확인해야 합니다. 핸들러 어댑터의 주요 목적은 디스패처 핸들러를 이러한 세부 정보로부터 보호하는 것입니다. |
HandlerResultHandler | 처리기 호출의 결과를 처리하고 응답을 완료합니다. 결과 처리를 참조하십시오. |
1.3.2. WebFlux Config
애플리케이션은 요청을 처리하는 데 필요한 인프라 Bean(웹 핸들러 API 및 DispatcherHandler 아래에 나열됨)을 선언할 수 있습니다. 그러나 대부분의 경우 WebFlux 구성이 가장 좋은 시작점입니다. 필요한 Bean을 선언하고 이를 사용자 정의하기 위한 상위 레벨 구성 콜백 API를 제공합니다.
스프링 부트는 WebFlux 구성에 의존하여 스프링 WebFlux를 구성하고 많은 편리한 옵션을 제공합니다.
1.3.3. Processing
디스패처 핸들러는 다음과 같이 요청을 처리합니다.
- 각 HandlerMapping은 일치하는 처리기를 찾도록 요청되고 첫 번째 일치 항목이 사용됩니다.
- 처리기가 발견되면 적절한 HandlerAdapter를 통해 실행되며, 이 어댑터는 실행의 반환 값을 HandlerResult로 노출합니다.
- 는 응답에 직접 쓰거나 렌더링할 뷰를 사용하여 처리를 완료하기 위해 적절한 HandlerResultHandler에 제공됩니다.
1.3.4. Result Handling
를 통해 처리기를 호출할 때 반환되는 값은 몇 가지 추가 컨텍스트와 함께 처리기 결과로 래핑되고 해당 처리기에 대한 지원을 클레임하는 첫 번째 처리기 결과처리기에 전달됩니다. 다음 표에서는 사용 가능한 HandlerResultHandler 구현을 보여 주며, 모두 WebFlux 구성에서 선언됩니다.
Result Handler Type | Return Values | Default Order |
ResponseEntityResultHandler | ResponseEntity, typically from @Controller instances. | 0 |
ServerResponseResultHandler | ServerResponse, typically from functional endpoints. | 0 |
ResponseBodyResultHandler | Handle return values from @ResponseBody methods or @RestController classes. | 100 |
ViewResolutionResultHandler | CharSequence, View, Model, Map, Rendering, or any other Object is treated as a model attribute. See also View Resolution. |
Integer.MAX_VALUE |
1.3.5. Exceptions
HandlerAdapter 구현은 컨트롤러 메서드와 같은 요청 처리기를 호출하는 내부 예외를 처리할 수 있습니다. 그러나 요청 처리기가 비동기 값을 반환하는 경우 예외가 지연될 수 있습니다.
는 예외 처리 메커니즘을 반환하는 HandlerResult에 설정된 DispatchExceptionHandler로 노출할 수 있습니다. 이 설정이 완료되면 DispatcherHandler는 결과 처리에도 이를 적용합니다.
HandlerAdapter는 DispatchExceptionHandler를 구현하도록 선택할 수도 있습니다. 이 경우 DispatcherHandler는 처리기가 매핑되기 전에 발생하는 예외(예: 처리기 매핑 중 또는 WebFilter 이전)에 적용합니다.
"주석 이 추가된 컨트롤러" 섹션의 예외 또는 WebHandler API 섹션의 예외도 참조하십시오.
1.3.6. View Resolution
뷰 해상도를 사용하면 특정 뷰 기술에 얽매이지 않고 HTML 템플릿과 모델을 사용하여 브라우저에 렌더링할 수 있습니다. 스프링 WebFlux에서 뷰 해상도는 ViewResolver 인스턴스를 사용하여 문자열(논리적 뷰 이름을 나타냄)을 View 인스턴스에 매핑하는 전용 HandlerResultHandler를 통해 지원됩니다. 그런 다음 뷰를 사용하여 응답을 렌더링합니다.
Handling
에 전달된 처리기 결과에는 처리기의 반환 값과 요청 처리 중에 추가된 특성이 포함된 모델이 포함됩니다. 반환 값은 다음 중 하나로 처리됩니다.
- String, CharSequence: 구성된 ViewResolver 구현 목록을 통해 View로 확인될 논리적 뷰 이름입니다.
- void: 요청 경로를 기준으로 선행 및 후행 슬래시를 뺀 기본 보기 이름을 선택하고 View로 확인합니다. 뷰 이름이 제공되지 않은 경우(예: 모델 특성이 반환됨) 비동기 반환 값(예: Mono가 비어 있음)인 경우에도 마찬가지입니다.
- Rendering: 뷰 확인 시나리오를 위한 API. 코드 완성을 통해 IDE의 옵션을 살펴봅니다.
- Model, Map: 요청에 대해 모델에 추가할 추가 모델 특성입니다.
- Any other: 다른 모든 리턴 값(BeanUtils#isSimpleProperty에 의해 판별되는 단순 유형 제외)은 모델에 추가될 모델 속성으로 처리됩니다. 특성 이름은 처리기 메서드 @ModelAttribute 주석이 없는 한 규칙을 사용하여 클래스 이름에서 파생됩니다.
모델에는 비동기식 반응형 유형(예: Reactor 또는 RxJava)이 포함될 수 있습니다. 렌더링하기 전에 AbstractView는 이러한 모델 특성을 구체적인 값으로 확인하고 모델을 업데이트합니다. 단일 값 반응형 유형은 단일 값 또는 값 없음(비어 있는 경우)으로 확인되는 반면, 다중 값 반응형 유형(예: Flux<T>)은 수집되어 List<T>로 확인됩니다.
뷰 해상도를 구성하는 것은 스프링 구성에 ViewResolutionResultHandler Bean을 추가하는 것만 큼 간단합니다. WebFlux 구성은 보기 확인을 위한 전용 구성 API를 제공합니다.
Spring WebFlux와 통합된 보기 기술에 대한 자세한 내용은 View Technologies를 참조하십시오.
Redirecting
뷰 이름의 특수 리디렉션: 접두사를 사용하면 리디렉션을 수행할 수 있습니다. UrlBasedViewResolver(및 하위 클래스)는 이를 리디렉션이 필요하다는 명령으로 인식합니다. 나머지 보기 이름은 리디렉션 URL입니다.
최종 효과는 컨트롤러가 RedirectView 또는 Rendering.redirectTo("abc").build()를 반환한 것과 동일하지만 이제 컨트롤러 자체가 논리적 뷰 이름으로 작동할 수 있습니다. redirect:/some/resource와 같은 보기 이름은 현재 애플리케이션에 상대적이지만 redirect:https://example.com/arbitrary/path 와 같은 보기 이름은 절대 URL로 리디렉션됩니다.
Content Negotiation
ViewResolutionResultHandler는 콘텐츠 협상을 지원합니다. 요청 미디어 유형을 선택한 각 보기에서 지원하는 미디어 유형과 비교합니다. 요청된 미디어 유형을 지원하는 첫 번째 뷰가 사용됩니다.
JSON 및 XML과 같은 미디어 유형을 지원하기 위해 Spring WebFlux는 HttpMessageWriter를 통해 렌더링되는 특수 뷰인 HttpMessageWriterView를 제공합니다. 일반적으로 WebFlux 구성을 통해 기본 보기로 구성합니다. 기본 보기는 요청된 미디어 유형과 일치하는 경우 항상 선택되어 사용됩니다.
1.4. Annotated Controllers
Spring WebFlux는 @Controller 및 @RestController 구성 요소가 주석을 사용하여 요청 매핑을 표현하고, 입력을 요청하고, 예외를 처리하는 등의 주석 기반 프로그래밍 모델을 제공합니다. 주석이 추가된 컨트롤러에는 유연한 메서드 서명이 있으며 기본 클래스를 확장하거나 특정 인터페이스를 구현할 필요가 없습니다.
다음 목록에서는 기본 예제를 보여 줍니다.
@RestController
class HelloController {
@GetMapping("/hello")
fun handle() = "Hello WebFlux"
}
앞의 예제에서 메서드는 응답 본문에 쓸 String을 반환합니다.
1.4.1. @Controller
표준 Spring Bean 정의를 사용하여 제어기 Bean을 정의할 수 있습니다. @Controller 스테레오타입은 자동 감지를 허용하며 클래스 경로에서 @Component 클래스를 감지하고 이에 대한 Bean 정의를 자동 등록하기 위한 Spring 일반 지원과 일치합니다. 또한 주석이 달린 클래스에 대한 스테레오타입 역할을 하여 웹 구성 요소로서의 역할을 나타냅니다.
이러한 @Controller Bean의 자동 감지를 사용하려면 다음 예제와 같이 Java 구성에 컴포넌트 스캐닝을 추가할 수 있습니다.
@Configuration
@ComponentScan("org.example.web")
class WebConfig {
// ...
}
@RestController는 자체적으로 @Controller 및 @ResponseBody로 메타 주석이 추가된 구성된 주석으로, 모든 메서드가 형식 수준 @ResponseBody 주석을 상속하므로 응답 본문에 직접 쓰는 컨트롤러와 뷰 해상도 및 HTML 템플릿을 사용한 렌더링을 나타냅니다.
AOP Proxies
경우에 따라 런타임에 AOP 프록시로 컨트롤러를 데코레이팅해야 할 수도 있습니다. 한 가지 예는 컨트롤러에 직접 @Transactional 주석을 포함하도록 선택하는 경우입니다. 이 경우 특히 컨트롤러의 경우 클래스 기반 프록시를 사용하는 것이 좋습니다. 이는 컨트롤러에서 직접 이러한 주석이 있는 경우에 자동으로 적용됩니다.
컨트롤러가 인터페이스를 구현하고 AOP 프록시가 필요한 경우 클래스 기반 프록시를 명시적으로 구성해야 할 수 있습니다. 예를 들어 @EnableTransactionManagement를 사용하면 @EnableTransactionManagement(proxyTargetClass = true)로 변경할 수 있고 <tx:annotation-driven/>를 사용하면 <tx:annotation-driven proxy-target-class="true"/>로 변경할 수 있습니다.
6.0부터 인터페이스 프록싱을 사용하면 Spring WebFlux는 더 이상 인터페이스의 유형 수준 @RequestMapping 주석만을 기반으로 컨트롤러를 감지하지 않습니다. 클래스 기반 프록시를 활성화하거나 그렇지 않으면 인터페이스에도 @Controller 주석이 있어야합니다.
1.4.2. Request Mapping
@RequestMapping 주석은 요청을 컨트롤러 메서드에 매핑하는 데 사용됩니다. URL, HTTP 메서드, 요청 매개 변수, 헤더 및 미디어 유형별로 일치하는 다양한 속성이 있습니다. 클래스 수준에서 공유 매핑을 표현하거나 메서드 수준에서 특정 끝점 매핑으로 범위를 좁힐 수 있습니다.
@RequestMapping의 HTTP 메서드별 바로 가기 변형도 있습니다.
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
- @PatchMapping
앞의 주석은 대부분의 컨트롤러 메서드가 기본적으로 모든 HTTP 메서드와 일치하는 @RequestMapping 사용하는 대신 특정 HTTP 메서드에 매핑되어야 하기 때문에 제공되는 사용자 지정 주석입니다. 동시에 공유 매핑을 표현하기 위해 클래스 수준에서 @RequestMapping가 여전히 필요합니다.
다음 예제에서는 형식 및 메서드 수준 매핑을 사용합니다.
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
fun getPerson(@PathVariable id: Long): Person {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
fun add(@RequestBody person: Person) {
// ...
}
}
URI Patterns
glob 패턴과 와일드카드를 사용하여 요청을 매핑할 수 있습니다.
Pattern | Description | Example |
? | 한 문자와 일치 | "/pages/t?st.html" matches "/pages/test.html" and "/pages/t3st.html" |
* | 경로 세그먼트 내에서 0개 이상의 문자와 일치 | "/resources/*.png" matches "/resources/file.png" "/projects/*/versions" matches "/projects/spring/versions" but does not match "/projects/spring/boot/versions" |
** | 경로의 끝까지 0개 이상의 경로 세그먼트와 일치합니다. | "/resources/**" matches "/resources/file.png" and "/resources/images/file.png" "/resources/**/file.png" is invalid as ** is only allowed at the end of the path. |
{name} | 경로 세그먼트를 일치시키고 "name"이라는 변수로 캡처합니다. | "/projects/{project}/versions" matches "/projects/spring/versions" and captures project=spring |
{name:[a-z]+} | 정규 표현식 "[a-z]+"를 "name"이라는 경로 변수와 일치시킵니다. | "/projects/{project:[a-z]+}/versions" matches "/projects/spring/versions" but not "/projects/spring1/versions" |
{*path} | 경로의 끝까지 0개 이상의 경로 세그먼트를 일치시키고 "path"라는 변수로 캡처합니다. | "/resources/{*file}" matches "/resources/images/file.png" and captures file=/images/file.png |
캡처된 URI 변수는 다음 예제와 같이 @PathVariable 사용하여 액세스할 수 있습니다.
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
// ...
}
다음 예제와 같이 클래스 및 메서드 수준에서 URI 변수를 선언할 수 있습니다.
@Controller
@RequestMapping("/owners/{ownerId}")
class OwnerController {
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
// ...
}
}
URI 변수가 자동으로 적절한 형식으로 변환되거나 TypeMismatchException이 발생합니다. 단순 형식(int, long, Date 등)이 기본적으로 지원되며 다른 데이터 형식에 대한 지원을 등록할 수 있습니다. 형식 변환 및 데이터 바인더를 참조하십시오.
URI 변수의 이름을 명시적으로 지정할 수 있지만(예: @PathVariable("customId")) 이름이 동일하고 -parameters 컴파일러 플래그를 사용하여 코드를 컴파일하는 경우 해당 세부 정보를 생략할 수 있습니다.
구문 {*varName}은 0개 이상의 나머지 경로 세그먼트와 일치하는 URI 변수를 선언합니다. 예를 들어 /resources/{*path}는 /resources/ 아래의 모든 파일과 일치하고 "path" 변수는 /resources의 전체 경로를 캡처합니다.
{varName:regex} 구문은 {varName:regex} 구문이 있는 정규식을 사용하여 URI 변수를 선언합니다. 예를 들어 URL이 /spring-web-3.0.5.jar인 경우 다음 메서드는 이름, 버전 및 파일 확장자를 추출합니다.
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
fun handle(@PathVariable version: String, @PathVariable ext: String) {
// ...
}
URI 경로 패턴에는 로컬, 시스템, 환경 및 기타 속성 소스에 대해 PropertySourcesPlaceholderConfigurer를 통해 시작 시 확인되는 포함된 ${...} 자리 표시자가 있을 수도 있습니다. 예를 들어 이를 사용하여 일부 외부 구성을 기반으로 기본 URL을 매개 변수화할 수 있습니다.
Spring WebFlux는 URI 경로 일치 지원을 위해 PathPattern 및 PathPatternParser를 사용합니다. 두 클래스 모두 스프링 웹에 있으며 런타임에 많은 URI 경로 패턴이 일치하는 웹 응용 프로그램에서 HTTP URL 경로와 함께 사용하도록 명시 적으로 설계되었습니다.
Spring WebFlux는 /person과 같은 매핑이 /person.*과도 일치하는 Spring MVC와 달리 접미사 패턴 일치를 지원하지 않습니다. URL 기반 콘텐츠 협상의 경우 필요한 경우 더 간단하고 명시적이며 URL 경로 기반 악용에 덜 취약한 쿼리 매개 변수를 사용하는 것이 좋습니다.
Pattern Comparison
여러 패턴이 URL과 일치하는 경우 가장 일치하는 패턴을 찾기 위해 비교해야 합니다. 이 작업은 보다 구체적인 패턴을 찾는 PathPattern.SPECIFICITY_COMPARATOR로 수행됩니다.
모든 패턴에 대해 URI 변수 및 와일드카드 수를 기준으로 점수가 계산되며, URI 변수의 점수는 와일드카드보다 낮습니다. 총점이 낮은 패턴이 승리합니다. 두 패턴의 점수가 같으면 더 긴 패턴이 선택됩니다.
범용 패턴(예: **, {*varName})은 점수 매기기에서 제외되며 항상 마지막에 정렬됩니다. 두 패턴이 모두 포괄적이면 더 긴 패턴이 선택됩니다.
Consumable Media Types
다음 예제와 같이 요청의 Content-Type을 기준으로 요청 매핑의 범위를 좁힐 수 있습니다.
@PostMapping("/pets", consumes = ["application/json"])
fun addPet(@RequestBody pet: Pet) {
// ...
}
consumes 특성은 부정 식도 지원합니다(예: !text/plain은 텍스트/일반 이외의 모든 콘텐츠 형식을 의미합니다).
클래스 수준에서 공유 소비 특성을 선언할 수 있습니다. 그러나 대부분의 다른 요청 매핑 특성과 달리 클래스 수준에서 사용되는 경우 메서드 수준은 클래스 수준 선언을 확장하는 대신 특성 재정의를 사용합니다.
MediaType은 일반적으로 사용되는 미디어 유형(예: APPLICATION_JSON_VALUE 및 APPLICATION_XML_VALUE)에 대한 상수를 제공합니다.
Producible Media Types
다음 예제와 같이 Accept request 헤더와 컨트롤러 메서드가 생성하는 콘텐츠 형식 목록을 기반으로 요청 매핑의 범위를 좁힐 수 있습니다.
@GetMapping("/pets/{petId}", produces = ["application/json"])
@ResponseBody
fun getPet(@PathVariable String petId): Pet {
// ...
}
미디어 유형은 문자 집합을 지정할 수 있습니다. 부정 표현식이 지원됩니다 — 예를 들어 !text/plain은 텍스트/일반 이외의 모든 콘텐츠 유형을 의미합니다.
클래스 수준에서 공유 생성 특성을 선언할 수 있습니다. 그러나 대부분의 다른 요청 매핑 특성과 달리 클래스 수준에서 사용되는 경우 메서드 수준은 클래스 수준 선언을 확장하는 대신 특성 재정의를 생성합니다.
MediaType은 일반적으로 사용되는 미디어 유형(예: APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE)에 대한 상수를 제공합니다.
Parameters and Headers
쿼리 매개 변수 조건에 따라 요청 매핑의 범위를 좁힐 수 있습니다. 쿼리 매개 변수가 있는지(myParam), 쿼리 매개 변수가 없는지(!myParam) 또는 특정 값(myParam=myValue)이 있는지 테스트할 수 있습니다. 다음 예제에서는 값이 있는 매개 변수를 테스트합니다.
@GetMapping("/pets/{petId}", params = ["myParam=myValue"])
fun findPet(@PathVariable petId: String) {
// ...
}
다음 예제와 같이 요청 헤더 조건과 동일하게 사용할 수도 있습니다.
@GetMapping("/pets", headers = ["myHeader=myValue"])
fun findPet(@PathVariable petId: String) {
// ...
}
HTTP HEAD, OPTIONS
@GetMapping 및 @RequestMapping(메서드=HttpMethod.GET)은 요청 매핑을 위해 HTTP HEAD를 투명하게 지원합니다. 컨트롤러 메서드는 변경할 필요가 없습니다. HttpHandler 서버 어댑터에 적용되는 응답 래퍼는 Content-Length 헤더가 실제로 응답에 쓰지 않고 기록된 바이트 수로 설정되도록 합니다.
기본적으로 HTTP 옵션은 URL 패턴이 일치하는 모든 @RequestMapping 메서드에 나열된 HTTP 메서드 목록으로 응답 허용 헤더를 설정하여 처리됩니다.
HTTP 메서드 선언이 없는 @RequestMapping의 경우 허용 헤더는 GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS로 설정됩니다. 컨트롤러 메서드는 항상 지원되는 HTTP 메서드를 선언해야 합니다(예: HTTP 메서드별 변형(@GetMapping, @PostMapping 등) 사용).
@RequestMapping 메서드를 HTTP HEAD 및 HTTP 옵션에 명시적으로 매핑할 수 있지만 일반적인 경우에는 필요하지 않습니다.
Custom Annotations
스프링 WebFlux는 요청 매핑을 위해 구성된 주석의 사용을 지원합니다. 그것들은 그 자체로 @RequestMapping로 메타 주석이 달리고 더 좁고 구체적인 목적으로 @RequestMapping 속성의 하위 집합(또는 전체)을 다시 선언하도록 구성된 주석입니다.
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping 및 @PatchMapping는 구성된 주석의 예입니다. 틀림없이 대부분의 컨트롤러 메서드는 기본적으로 모든 HTTP 메서드와 일치하는 @RequestMapping 사용하는 대신 특정 HTTP 메서드에 매핑되어야 하기 때문에 제공됩니다. 작성된 주석의 예가 필요한 경우 주석이 선언되는 방법을 살펴보십시오.
Spring WebFlux는 사용자 지정 요청 일치 논리를 사용하여 사용자 지정 요청 매핑 속성도 지원합니다. 이 옵션은 RequestMappingHandlerMapping을 서브클래싱하고 getCustomMethodCondition 메서드를 재정의해야 하는 고급 옵션으로, 사용자 지정 특성을 확인하고 사용자 고유의 RequestCondition을 반환할 수 있습니다.
Explicit Registrations
동적 등록 또는 고급 사례(예: 다른 URL에 있는 동일한 처리기의 다른 인스턴스)에 사용할 수 있는 Handler 메서드를 프로그래밍 방식으로 등록할 수 있습니다. 다음 예제에서는 이 작업을 수행하는 방법을 보여 줍니다.
@Configuration
class MyConfig {
@Autowired
fun setHandlerMapping(mapping: RequestMappingHandlerMapping, handler: UserHandler) {
val info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build()
val method = UserHandler::class.java.getMethod("getUser", Long::class.java)
mapping.registerMapping(info, handler, method)
}
}
1.4.3. Handler Methods
@RequestMapping handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values.
Explicit Registrations
다음 표에서는 지원되는 컨트롤러 메서드 인수를 보여 줍니다.
반응형 유형(Reactor, RxJava 또는 기타)은 I/O 차단(예: 요청 본문 읽기)을 확인해야 하는 인수에서 지원됩니다. 이것은 설명 열에 표시됩니다. 반응형 형식은 차단이 필요하지 않은 인수에는 필요하지 않습니다.
JDK 1.8의 java.util.Optional은 필수 속성(예: @RequestParam, @RequestHeader 등)이 있는 주석과 함께 메서드 인수로 지원되며 required=false와 동일합니다.
Controller method argument | Description |
ServerWebExchange | 전체 ServerWebExchange에 대한 액세스 — HTTP 요청 및 응답, 요청 및 세션 속성, checkNotModified 메서드 등에 대한 컨테이너입니다. |
ServerHttpRequest, ServerHttpResponse | HTTP 요청 또는 응답에 액세스합니다. |
WebSession | 세션에 액세스합니다. 이렇게 하면 특성이 추가되지 않는 한 새 세션이 강제로 시작되지 않습니다. 반응형 유형을 지원합니다. |
java.security.Principal | 현재 인증된 사용자 — 알려진 경우 특정 Principal 구현 클래스일 수 있습니다. 반응형 유형을 지원합니다. |
org.springframework.http.HttpMethod | Requests의 HTTP 메서드입니다. |
java.util.Locale | 사용 가능한 가장 구체적인 로캘 확인자, 즉 실제로 구성된 LocaleResolver/LocaleContextResolver에 의해 결정되는 현재 요청 로캘입니다. |
java.util.TimeZone + java.time.ZoneId | 현재 요청과 연결된 표준 시간대로, 로캘컨텍스트 확인자에 의해 결정됩니다. |
@PathVariable | URI 템플릿 변수에 액세스합니다. URI 패턴을 참조하십시오. |
@MatrixVariable | URI 경로 세그먼트의 이름-값 쌍에 액세스합니다. 행렬 변수를 참조하십시오. |
@RequestParam | 쿼리 매개 변수에 액세스합니다. 매개 변수 값은 선언된 메서드 인수 형식으로 변환됩니다. @RequestParam 참조하십시오. @RequestParam 사용은 선택 사항입니다(예: 속성 설정). 이 표의 뒷부분에 있는 "다른 인수"를 참조하십시오. |
@RequestHeader | 요청 헤더에 액세스합니다. 헤더 값은 선언된 메서드 인수 형식으로 변환됩니다. @RequestHeader 참조하십시오. |
@CookieValue | 쿠키에 액세스하기 위해. 쿠키 값은 선언된 메서드 인수 형식으로 변환됩니다. @CookieValue 참조하십시오. |
@RequestBody | HTTP 요청 본문에 액세스합니다. 본문 콘텐츠는 HttpMessageReader 인스턴스를 사용하여 선언된 메서드 인수 형식으로 변환됩니다. 반응형 유형을 지원합니다. @RequestBody 참조하십시오. |
HttpEntity<B> | 요청 헤더 및 본문에 액세스합니다. 본문은 HttpMessageReader 인스턴스로 변환됩니다. 반응형 유형을 지원합니다. 를 참조하십시오. |
@RequestPart | 다중 파트/양식 데이터 요청의 부품에 액세스합니다. 반응형 유형을 지원합니다. 다중 파트 콘텐츠 및 다중 파트 데이터를 참조하십시오. |
java.util.Map, org.springframework.ui.Model, and org.springframework.ui.ModelMap. | HTML 컨트롤러에서 사용되고 뷰 렌더링의 일부로 템플릿에 노출되는 모델에 액세스합니다. |
@ModelAttribute | 데이터 바인딩 및 유효성 검사가 적용된 모델의 기존 특성(없는 경우 인스턴스화됨)에 액세스합니다. @ModelAttribute와 모델 및 DataBinder를 참조하십시오. @ModelAttribute 사용은 선택 사항입니다(예: 해당 속성 설정). 이 표의 뒷부분에 있는 "다른 인수"를 참조하십시오. |
Errors, BindingResult | 명령 객체에 대한 유효성 검사 및 데이터 바인딩의 오류에 액세스하기 위해 (예 : @ModelAttribute 인수). 오류 또는 BindingResult 인수는 유효성이 검사된 메서드 인수 바로 뒤에 선언해야 합니다. |
SessionStatus + class-level @SessionAttributes | 양식 처리를 완료로 표시하기 위해 클래스 수준 @SessionAttributes 주석을 통해 선언된 세션 속성의 정리를 트리거합니다. 자세한 내용은 @SessionAttributes 참조하십시오. |
UriComponentsBuilder | 현재 요청의 호스트, 포트, 체계 및 컨텍스트 경로에 상대적인 URL을 준비하는 데 사용됩니다. URI 링크를 참조하십시오. |
@SessionAttribute | 모든 세션 속성에 대한 액세스 — 클래스 수준 @SessionAttributes 선언의 결과로 세션에 저장된 모델 속성과 대조됩니다. 자세한 내용은 @SessionAttribute 참조하십시오. |
@RequestAttribute | 요청 속성에 액세스합니다. 자세한 내용은 @RequestAttribute 참조하십시오. |
Any other argument | 메소드 인수가 위의 항목과 일치하지 않는 경우, 기본적으로 BeanUtils#isSimpleProperty에 의해 판별되는 단순 유형인 경우 @RequestParam으로 해석되고, 그렇지 않으면 @ModelAttribute로 해석됩니다. |
Return Values
The following table shows the supported controller method return values. Note that reactive types from libraries such as Reactor, RxJava, or other are generally supported for all return values.
Controller method return value | Description |
@ResponseBody | 반환 값은 HttpMessageWriter 인스턴스를 통해 인코딩되고 응답에 기록됩니다. @ResponseBody 참조하십시오. |
HttpEntity<B>, ResponseEntity<B> | 반환 값은 HTTP 헤더를 포함한 전체 응답을 지정하며 본문은 HttpMessageWriter 인스턴스를 통해 인코딩되어 응답에 기록됩니다. ResponseEntity를 참조하십시오. |
HttpHeaders | 헤더가 있고 본문이 없는 응답을 반환합니다. |
ErrorResponse | 본문에 세부 정보가 포함된 RFC 7807 오류 응답을 렌더링하려면 오류 응답을 참조하십시오. |
ProblemDetail | 본문에 세부 정보가 포함된 RFC 7807 오류 응답을 렌더링하려면 오류 응답을 참조하십시오. |
String | ViewResolver 인스턴스로 확인되고 암시적 모델과 함께 사용되는 뷰 이름으로, 명령 개체 및 @ModelAttribute 메서드를 통해 결정됩니다. 처리기 메서드는 앞에서 설명한 Model 인수를 선언하여 프로그래밍 방식으로 모델을 보강할 수도 있습니다. |
View | 암시적 모델과 함께 렌더링하는 데 사용할 View 인스턴스로, 명령 개체와 @ModelAttribute 메서드를 통해 결정됩니다. 처리기 메서드는 앞에서 설명한 Model 인수를 선언하여 프로그래밍 방식으로 모델을 보강할 수도 있습니다. |
java.util.Map, org.springframework.ui.Model | 암시적 모델에 추가할 특성으로, 뷰 이름은 요청 경로에 따라 암시적으로 결정됩니다. |
@ModelAttribute | 모델에 추가할 특성으로, 뷰 이름은 요청 경로에 따라 암시적으로 결정됩니다. @ModelAttribute 선택 사항입니다. 이 표의 뒷부분에 있는 "다른 반환 값"을 참조하십시오. |
Rendering | 모델 및 뷰 렌더링 시나리오를 위한 API입니다. |
void | 비동기적일 수 있는 void(예: Mono<Void>), 반환 형식(또는 null 반환 값)이 있는 메서드는 ServerHttpResponse, ServerWebExchange 인수 또는 @ResponseStatus 주석도 있는 경우 응답을 완전히 처리한 것으로 간주됩니다. 컨트롤러가 긍정적인 ETag 또는 lastModified 타임스탬프 검사를 수행한 경우에도 마찬가지입니다. 자세한 내용은 컨트롤러를 참조하십시오. 위의 어느 것도 참이 아닌 경우 void 반환 유형은 REST 컨트롤러에 대해 "응답 본문 없음" 또는 HTML 제어기에 대한 기본 보기 이름 선택을 나타낼 수도 있습니다. |
Flux<ServerSentEvent>, Observable<ServerSentEvent>, or other reactive type | 서버에서 보낸 이벤트를 내보냅니다. ServerSentEvent 래퍼는 데이터만 써야 하는 경우 생략할 수 있습니다(단, produce 특성을 통해 매핑에서 텍스트/이벤트 스트림을 요청하거나 선언해야 함). |
Other return values | 리턴 값이 다른 방식으로 해석되지 않은 상태로 남아 있는 경우, BeanUtils#isSimpleProperty에 의해 판별된 단순 유형이 아닌 한, 이는 모델 속성으로 처리되며, 이 경우 해석되지 않은 상태로 남아 있습니다. |
Type Conversion
String 기반 요청 입력을 나타내는 일부 주석이 추가된 컨트롤러 메서드 인수(예: @RequestParam, @RequestHeader, @PathVariable, @MatrixVariable 및 @CookieValue)는 인수가 String이 아닌 다른 것으로 선언된 경우 형식 변환이 필요할 수 있습니다.
이러한 경우 형식 변환은 구성된 변환기에 따라 자동으로 적용됩니다. 기본적으로 단순 형식(예: int, long, Date 등)이 지원됩니다. 형식 변환은 WebDataBinder(DataBinder 참조) 또는 포맷팅변환서비스에 포맷터를 등록하여(Spring 필드 포맷팅 참조) 사용자 지정할 수 있습니다.
형식 변환의 실질적인 문제는 빈 String 소스 값을 처리하는 것입니다. 이러한 값은 형식 변환의 결과로 null이 되는 경우 누락된 것으로 처리됩니다. 이는 Long, UUID 및 기타 대상 유형의 경우일 수 있습니다. null을 삽입할 수 있도록 하려면 인수 주석에 필수 플래그를 사용하거나 인수를 @Nullable로 선언합니다.
Matrix Variables
RFC 3986에서는 경로 세그먼트의 이름-값 쌍에 대해 설명합니다. Spring WebFlux에서는 Tim Berners-Lee의 "이전 게시물"을 기반으로 한 "행렬 변수"라고 부르지만 URI 경로 매개 변수라고도 할 수 있습니다.
행렬 변수는 각 변수를 세미콜론으로 구분하고 여러 값을 쉼표로 구분하여 모든 경로 세그먼트에 나타날 수 있습니다(예: "/cars;color=red,green;year=2012"). 반복되는 변수 이름을 통해 여러 값을 지정할 수도 있습니다(예: "color=red;color=green;color=blue").
스프링 MVC와 달리 WebFlux에서는 URL에 행렬 변수가 있는지 여부가 요청 매핑에 영향을 미치지 않습니다. 즉, URI 변수를 사용하여 변수 콘텐츠를 마스킹할 필요가 없습니다. 즉, 컨트롤러 메서드에서 행렬 변수에 액세스하려면 행렬 변수가 예상되는 경로 세그먼트에 URI 변수를 추가해야 합니다. 다음 예제에서는 이 작업을 수행하는 방법을 보여 줍니다.
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) {
// petId == 42
// q == 11
}
모든 경로 세그먼트에 행렬 변수가 포함될 수 있으므로 다음 예제와 같이 행렬 변수가 포함될 것으로 예상되는 경로 변수를 명확하게 해야 할 수도 있습니다.
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable(name = "q", pathVar = "ownerId") q1: Int,
@MatrixVariable(name = "q", pathVar = "petId") q2: Int) {
// q1 == 11
// q2 == 22
}
행렬 변수를 선택적으로 정의하고 다음 예제와 같이 기본값을 지정할 수 있습니다.
// GET /pets/42
@GetMapping("/pets/{petId}")
fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) {
// q == 1
}
모든 행렬 변수를 가져오려면 다음 예제와 같이 MultiValueMap을 사용합니다.
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
@MatrixVariable matrixVars: MultiValueMap<String, String>,
@MatrixVariable(pathVar="petId") petMatrixVars: MultiValueMap<String, String>) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
@RequestParam
@RequestParam 주석을 사용하여 쿼리 매개 변수를 컨트롤러의 메서드 인수에 바인딩할 수 있습니다. 다음 코드 조각은 사용법을 보여 줍니다.
@Controller
@RequestMapping("/pets")
class EditPetForm {
// ...
@GetMapping
fun setupForm(@RequestParam("petId") petId: Int, model: Model): String {
val pet = clinic.loadPet(petId)
model["pet"] = pet
return "petForm"
}
// ...
}
Servlet API "요청 매개변수" 개념은 쿼리 매개변수, 양식 데이터 및 멀티파트를 하나로 통합합니다. 그러나 WebFlux에서는 ServerWebExchange를 통해 각각에 개별적으로 액세스됩니다. @RequestParam 쿼리 매개 변수에만 바인딩되지만 데이터 바인딩을 사용하여 쿼리 매개 변수, 양식 데이터 및 다중 파트를 명령 개체에 적용할 수 있습니다.
@RequestParam 어노테이션을 사용하는 메소드 매개변수는 기본적으로 필요하지만 @RequestParam의 필수 플래그를 false로 설정하거나 java.util.Optional 래퍼를 사용하여 인수를 선언하여 메소드 매개변수가 선택사항임을 지정할 수 있습니다.
형식 변환은 대상 메서드 매개 변수 형식이 String이 아닌 경우 자동으로 적용됩니다. 형식 변환을 참조하십시오.
@RequestParam 주석이 Map<String, String> 또는 MultiValueMap<String, String> 인수에 선언되면 맵은 모든 쿼리 매개 변수로 채워집니다.
@RequestParam 사용은 선택 사항입니다(예: 속성 설정). 기본적으로 단순 값 유형(BeanUtils#isSimpleProperty에 의해 판별됨)이고 다른 인수 해석기에 의해 해석되지 않는 인수는 @RequestParam로 어노테이션이 추가된 것처럼 처리됩니다.