Spring MVC는 @Controller 및 @RestController component가 annotation을 사용하여 요청 매핑, 요청 입력, 예외 처리 등을 표현하는 annotation 기반 프로그래밍 모델을 제공합니다. annotation이 달린 컨트롤러는 유연한 메서드 서명을 가지고 있으며 기본 클래스를 확장하거나 특정 인터페이스를 구현할 필요가 없습니다. 다음 예는 annotation으로 정의된 컨트롤러를 보여줍니다.
@Controller
public class HelloController {
@GetMapping("/hello")
public String handle(Model model) {
model.addAttribute("message", "Hello World!");
return "index";
}
}
앞의 예에서 메서드는 모델을 받아들이고 뷰 이름을 문자열로 반환하지만 다른 많은 옵션이 존재하며 이 장의 뒷부분에서 설명합니다.
spring.io의 가이드와 튜토리얼은 이 섹션에서 설명하는 annotation 기반 프로그래밍 모델을 사용합니다.
서블릿의 WebApplicationContext에서 표준 Spring 빈 정의를 사용하여 컨트롤러 빈을 정의할 수 있습니다. @Controller 스테레오타입은 클래스 경로에서 @Component 클래스를 감지하고 이에 대한 빈 정의를 자동 등록하기 위한 Spring 일반 지원과 정렬된 자동 감지를 허용합니다. 또한 annotation이 달린 클래스에 대한 스테레오타입 역할을 하여 웹 component로서의 역할을 나타냅니다.
이러한 @Controller 빈의 자동 감지를 활성화하려면 다음 예제와 같이 구성 요소 스캔을 Java 구성에 추가할 수 있습니다.
@Configuration
@ComponentScan("org.example.web")
public class WebConfig {
// ...
}
다음 예는 앞의 예와 동일한 XML 구성을 보여줍니다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example.web"/>
<!-- ... -->
</beans>
@RestController는 모든 메소드가 유형 수준 @ResponseBody annotateion을 상속하는 컨트롤러를 나타내기 위해 @Controller 및 @ResponseBody로 메타 annotation이 달린 composed anootation이므로 view resolution 및 HTML template 렌더링과 달리 응답 본문을 직접 작성합니다.
어떤 경우에는 런타임에 AOP 프록시로 컨트롤러를 장식해야 할 수도 있습니다. 한 가지 예는 컨트롤러에서 직접 @Transactional 주석을 사용하도록 선택한 경우입니다. 이 경우, 특히 컨트롤러의 경우, 클래스 기반 프록시를 사용하는 것이 좋습니다. 이것은 일반적으로 컨트롤러의 기본 선택입니다. 그러나 컨트롤러가 Spring Context 콜백이 아닌 인터페이스(예: InitializingBean, *Aware 등)를 구현해야 하는 경우 클래스 기반 프록시를 명시적으로 구성해야 할 수 있습니다. 예를 들어 <tx:annotation-driven/>을 사용하면 <tx:annotation-driven proxy-target-class="true"/>로 변경할 수 있고 @EnableTransactionManagement를 사용하면 @EnableTransactionManagement(proxyTargetClass = true)로 변경할 수 있습니다.
@RequestMapping annotation을 사용하여 요청을 컨트롤러 메서드에 매핑할 수 있습니다. URL, HTTP 메서드, 요청 매개 변수, 헤더 및 미디어 유형별로 일치하는 다양한 속성이 있습니다. 클래스 수준에서 이를 사용하여 공유 매핑을 표현하거나 메서드 수준에서 특정 끝점 매핑으로 범위를 좁힐 수 있습니다.
@RequestMapping의 HTTP 메서드 특정 바로 가기 변형도 있습니다.
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
바로 가기는 대부분의 컨트롤러 메서드가 기본적으로 모든 HTTP 메서드와 일치하는 @RequestMapping을 사용하는 대신 특정 HTTP 메서드에 매핑되어야 하기 때문에 제공되는 Custom Annotation입니다. @RequestMapping은 공유 매핑을 표현하기 위해 클래스 수준에서 여전히 필요합니다.
다음 예제에는 유형 및 메서드 수준 매핑이 있습니다.
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
@RequestMapping 메서드는 URL 패턴을 사용하여 매핑할 수 있습니다. 두 가지 대안이 있습니다.
PathPattern - PathContainer로도 미리 구문 분석된 URL 경로와 일치하는 미리 구문 분석된 패턴입니다. 웹용으로 설계된 이 솔루션은 인코딩 및 경로 매개변수를 효과적으로 처리하고 효율적으로 일치시킵니다.
AntPathMatcher - 문자열 경로에 대해 문자열 패턴을 일치시킵니다. 이것은 클래스 경로, 파일 시스템 및 기타 위치에서 리소스를 선택하기 위해 Spring 구성에서도 사용되는 원래 솔루션입니다. 덜 효율적이고 문자열 경로 입력은 URL의 인코딩 및 기타 문제를 효과적으로 처리하는 데 어려움이 있습니다.
PathPattern은 웹 애플리케이션에 권장되는 솔루션이며 Spring WebFlux에서 유일한 선택입니다. 버전 5.3 이전에는 AntPathMatcher가 Spring MVC의 유일한 선택이었고 계속 기본값입니다. 그러나 PathPattern은 MVC 구성에서 활성화할 수 있습니다.
PathPattern은 AntPathMatcher와 동일한 패턴 구문을 지원합니다. 또한 캡처 패턴도 지원합니다. {*spring}, 경로 끝에서 0개 이상의 경로 세그먼트를 일치시킵니다. PathPattern은 또한 패턴의 끝에서만 허용되도록 여러 경로 세그먼트를 일치시키는 데 **사용을 제한합니다. 이렇게 하면 주어진 요청에 대해 가장 잘 일치하는 패턴을 선택할 때 많은 경우의 모호성이 제거됩니다. 전체 패턴 구문은 PathPattern 및 AntPathMatcher를 참조하십시오.
몇 가지 예시 패턴:
"/resources/ima?e.png" - 경로 세그먼트의 한 문자와 일치
"/resources/*.png" - 경로 세그먼트에서 0개 이상의 문자와 일치
"/resources/**" - 여러 경로 세그먼트와 일치
"/projects/{project}/versions" - 경로 세그먼트를 일치시키고 변수로 캡처
"/projects/{project:[a-z]+}/versions" - 정규식으로 변수를 일치시키고 캡처합니다.
캡처된 URI 변수는 @PathVariable을 사용하여 액세스할 수 있습니다. 예를 들어:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
다음 예제와 같이 클래스 및 메서드 수준에서 URI 변수를 선언할 수 있습니다.
@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {
@GetMapping("/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
}
URI 변수는 자동으로 적절한 유형으로 변환되거나 TypeMismatchException이 발생합니다. 단순 유형(int, long, Date 등)은 기본적으로 지원되며 다른 모든 데이터 유형에 대한 지원을 등록할 수 있습니다. Type Conversion 및 DataBinder를 참조하십시오.
URI 변수의 이름을 명시적으로 지정할 수 있지만(예: @PathVariable("customId")), 이름이 동일하고 코드가 디버깅 정보로 컴파일되거나 Java 8에서 -parameters 컴파일러 플래그를 사용하여 컴파일된 경우 해당 세부정보를 생략할 수 있습니다. .
{varName:regex} 구문은 {varName:regex} 구문이 있는 정규식을 사용하여 URI 변수를 선언합니다. 예를 들어 URL이 "/spring-web-3.0.5.jar"인 경우 다음 메서드는 이름, 버전 및 파일 확장자를 추출합니다.
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
// ...
}
URI 경로 패턴에는 로컬, 시스템, 환경 및 기타 속성 소스에 대해 PropertyPlaceHolderConfigurer를 사용하여 시작 시 확인되는 포함된 ${… } 자리 표시자가 있을 수도 있습니다. 예를 들어 이를 사용하여 일부 외부 구성을 기반으로 기본 URL을 매개변수화할 수 있습니다.
여러 패턴이 URL과 일치하는 경우 가장 일치하는 항목을 선택해야 합니다. 이것은 구문 분석된 PathPattern 사용이 사용 가능한지 여부에 따라 다음 중 하나로 수행됩니다.
PathPattern.SPECIFICITY_COMPARATOR
AntPathMatcher.getPatternComparator(String path)
둘 다 더 구체적인 패턴을 맨 위에 놓고 패턴을 정렬하는 데 도움이 됩니다. 패턴은 URI 변수(1로 계산), 단일 와일드카드(1로 계산) 및 이중 와일드카드(2로 계산)의 수가 적은 경우 덜 구체적입니다. 동일한 점수가 주어지면 더 긴 패턴이 선택됩니다. 동일한 점수와 길이가 주어지면 와일드카드보다 URI 변수가 더 많은 패턴이 선택됩니다.
기본 매핑 패턴(/**)은 채점에서 제외되며 항상 마지막에 정렬됩니다. 또한 접두사 패턴(예: /public/**)은 이중 와일드카드가 없는 다른 패턴보다 덜 구체적인 것으로 간주됩니다.
자세한 내용은 위의 패턴 비교기 링크를 참조하세요.
5.3부터 기본적으로 Spring MVC는 더 이상 /person에 매핑된 컨트롤러가 /person.*에 암시적으로 매핑되는 .* 접미사 패턴 일치를 수행하지 않습니다. 결과적으로 경로 확장은 더 이상 응답에 대한 요청된 콘텐츠 유형(예: /person.pdf, /person.xml 등)을 해석하는 데 사용되지 않습니다.
이러한 방식으로 파일 확장자를 사용하는 것은 브라우저가 일관되게 해석하기 어려운 Accept 헤더를 보낼 때 필요했습니다. 현재로서는 더 이상 필요하지 않으며 Accept 헤더를 사용하는 것이 선호되는 선택입니다.
시간이 지남에 따라 파일 이름 확장자의 사용은 다양한 방식으로 문제가 있음이 입증되었습니다. URI 변수, 경로 매개변수 및 URI 인코딩을 사용하는 경우 모호성이 발생할 수 있습니다. URL 기반 권한 부여 및 보안에 대한 추론(자세한 내용은 다음 섹션 참조)도 더 어려워집니다.
5.3 이전 버전에서 경로 확장 사용을 완전히 비활성화하려면 다음을 설정하십시오.
useSuffixPatternMatching(false), PathMatchConfigurer 참조
favorPathExtension(false), ContentNegotiationConfigurer 참조
"Accept" 헤더를 통하지 않고 콘텐츠 유형을 요청하는 방법이 있으면 여전히 유용할 수 있습니다. 브라우저에 URL을 입력할 때 경로 확장에 대한 안전한 대안은 쿼리 매개변수 전략을 사용하는 것입니다. 파일 확장자를 사용해야 하는 경우 ContentNegotiationConfigurer의 mediaType 속성을 통해 명시적으로 등록된 확장자 목록으로 제한하는 것이 좋습니다.
RFD(반사 파일 다운로드) 공격은 응답에 반영되는 요청 입력(예: 쿼리 매개변수 및 URI 변수)에 의존한다는 점에서 XSS와 유사합니다. 그러나 HTML에 JavaScript를 삽입하는 대신 RFD 공격은 브라우저 전환에 의존하여 다운로드를 수행하고 나중에 더블 클릭할 때 응답을 실행 가능한 스크립트로 처리합니다.
Spring MVC에서 @ResponseBody 및 ResponseEntity 메소드는 클라이언트가 URL 경로 확장을 통해 요청할 수 있는 다른 컨텐츠 유형을 렌더링할 수 있기 때문에 위험합니다. 접미사 패턴 일치를 비활성화하고 콘텐츠 협상을 위해 경로 확장을 사용하면 위험이 줄어들지만 RFD 공격을 방지하기에 충분하지 않습니다.
RFD 공격을 방지하기 위해 응답 본문을 렌더링하기 전에 Spring MVC는 Content-Disposition:inline;filename=f.txt 헤더를 추가하여 고정되고 안전한 다운로드 파일을 제안합니다. 이는 URL 경로에 안전한 것으로 허용되지 않거나 콘텐츠 협상을 위해 명시적으로 등록되지 않은 파일 확장자가 포함된 경우에만 수행됩니다. 그러나 URL이 브라우저에 직접 입력되는 경우 잠재적으로 부작용이 있을 수 있습니다.
많은 공통 경로 확장이 기본적으로 안전한 것으로 허용됩니다. 사용자 지정 HttpMessageConverter 구현이 있는 응용 프로그램은 콘텐츠 협상을 위해 파일 확장자를 명시적으로 등록하여 해당 확장에 Content-Disposition 헤더가 추가되는 것을 방지할 수 있습니다. Content Types을 참조하십시오.
RFD와 관련된 추가 권장 사항은 CVE-2015-5211을 참조하십시오.
다음 예제와 같이 요청의 Content-Type을 기반으로 요청 매핑을 좁힐 수 있습니다.
@PostMapping(path = "/pets", consumes = "application/json") // (1)
public void addPet(@RequestBody Pet pet) {
// ...
}
(1) consumes 속성을 사용하여 콘텐츠 유형별로 매핑 범위를 좁힙니다.
consumes 속성은 또한 부정 표현 을 지원합니다. 예를 들어 !text/plain은 text/plain 이외의 모든 콘텐츠 유형을 의미합니다.
클래스 수준에서 공유 consumes 속성을 선언할 수 있습니다. 그러나 대부분의 다른 요청 매핑 속성과 달리 클래스 수준에서 사용할 때, 메서드 수준은 클래스 수준 선언을 확장하는 대신 consumes속성 재정의를 사용합니다.
MediaType은APPLICATION_JSON_VALUE및APPLICATION_XML_VALUE와 같이 일반적으로 사용되는 미디어 유형에 대한 상수를 제공합니다.
다음 예제와 같이 Accept 요청 헤더와 컨트롤러 메서드가 생성하는 콘텐츠 유형 목록을 기반으로 요청 매핑을 좁힐 수 있습니다.
@GetMapping(path = "/pets/{petId}", produces = "application/json") // (1)
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
(1) produces 속성을 사용하여 콘텐츠 유형별로 매핑 범위를 좁힙니다.
미디어 유형은 문자 집합을 지정할 수 있습니다. 부정 표현식이 지원됩니다 — 예를 들어 !text/plain은 "text/plain"이 아닌 모든 콘텐츠 유형을 의미합니다.
클래스 수준에서 공유 produces 속성을 선언할 수 있습니다. 그러나 대부분의 다른 요청 매핑 속성과 달리 클래스 수준에서 사용할 때, 메서드 수준은 클래스 수준 선언을 확장하는 대신 produces 속성 재정의를 생성합니다.
MediaType은APPLICATION_JSON_VALUE및APPLICATION_XML_VALUE와 같이 일반적으로 사용되는 미디어 유형에 대한 상수를 제공합니다.
요청 매개변수 조건에 따라 요청 매핑을 좁힐 수 있습니다. 요청 매개변수가 있는지(myParam), 없는지(!myParam) 또는 특정 값(myParam=myValue)이 있는지 테스트할 수 있습니다. 다음 예에서는 특정 값을 테스트하는 방법을 보여줍니다.
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") // (1)
public void findPet(@PathVariable String petId) {
// ...
}
(1) myParam이 myValue와 같은지 테스트합니다.
다음 예제와 같이 요청 헤더 조건에도 동일하게 사용할 수 있습니다.
@GetMapping(path = "/pets", headers = "myHeader=myValue") // (1)
public void findPet(@PathVariable String petId) {
// ...
}
(1) myHeader이 myValue와 같은지 테스트합니다.
Content-Type및Accept를 헤더 조건과 일치시킬 수 있지만 대신 consumes 및 produces을 사용하는 것이 좋습니다.
@GetMapping(및 @RequestMapping(method=HttpMethod.GET))은 요청 매핑을 위해 투명하게 HTTP HEAD를 지원합니다. 컨트롤러 메서드는 변경할 필요가 없습니다. javax.servlet.http.HttpServlet에 적용된 응답 래퍼는 Content-Length 헤더가 실제로 응답에 쓰지 않고 작성된 바이트 수로 설정되도록 합니다.
@GetMapping(및 @RequestMapping(method=HttpMethod.GET))은 암시적으로 HTTP HEAD에 매핑되고 지원됩니다. HTTP HEAD 요청은 본문을 쓰는 대신 바이트 수가 계산되고 Content-Length 헤더가 설정된다는 점을 제외하고는 HTTP GET인 것처럼 처리됩니다.
기본적으로 HTTP OPTIONS는 일치하는 URL 패턴이 있는 모든 @RequestMapping 메서드에 나열된 HTTP 메서드 목록에 대해 Allow 응답 헤더를 설정하여 처리됩니다.
HTTP 메서드 선언이 없는 @RequestMapping의 경우 Allow 헤더가 GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS로 설정됩니다. 컨트롤러 메서드는 항상 지원되는 HTTP 메서드를 선언해야 합니다(예: HTTP 메서드 특정 변형: @GetMapping, @PostMapping 등 사용).
@RequestMapping 메서드를 HTTP HEAD 및 HTTP OPTIONS에 명시적으로 매핑할 수 있지만 일반적인 경우에는 필요하지 않습니다.
Spring MVC는 요청 매핑을 위해 composed annotations의 사용을 지원합니다. 그것들은 @RequestMapping으로 meta-annotation 이 달렸고 더 좁고 더 구체적인 목적으로 @RequestMapping 속성의 하위 집합(또는 모두)을 다시 선언하도록 구성된 annotation입니다.
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping은 composed annotations의 예입니다. 대부분의 컨트롤러 메서드는 기본적으로 모든 HTTP 메서드와 일치하는 @RequestMapping을 사용하는 대신 특정 HTTP 메서드에 매핑되어야 하기 때문에 제공됩니다. composed annotations의 예가 필요한 경우, composed annotations이 어떻게 선언되는지 확인하십시오.
Spring MVC는 또한 사용자 정의 요청 일치 논리로 사용자 정의 요청 매핑 속성을 지원합니다. 이것은 RequestMappingHandlerMapping을 서브클래싱하고 getCustomMethodCondition 메소드를 재정의해야 하는 고급 옵션입니다. 여기서 사용자 정의 속성을 확인하고 고유한 RequestCondition을 반환할 수 있습니다.
프로그래밍 방식으로 hanlder 메서드를 등록할 수 있습니다. 이 메서드는 동적 등록이나 다른 URL에 있는 동일한 handler의 다른 인스턴스와 같은 고급 사례에 사용할 수 있습니다. 다음 예제에서는 handler 메서드를 등록합니다.
@Configuration
public class MyConfig {
@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) // (1)
throws NoSuchMethodException {
RequestMappingInfo info = RequestMappingInfo
.paths("/user/{id}").methods(RequestMethod.GET).build(); // (2)
Method method = UserHandler.class.getMethod("getUser", Long.class); // (3)
mapping.registerMapping(info, handler, method); // (4)
}
}
(1) 컨트롤러에 대한 대상 핸들러 및 핸들러 매핑을 주입합니다.
(2) 요청 매핑 메타 데이터를 준비합니다.
(3) 핸들러 메서드를 가져옵니다.
(4) 등록을 추가합니다.
@RequestMapping 핸들러 메서드는 유연한 서명을 가지고 있으며 지원되는 컨트롤러 메서드 인수 및 반환 값 범위에서 선택할 수 있습니다.
다음 표에서는 지원되는 컨트롤러 메서드 인수에 대해 설명합니다. 반응형 유형은 인수에 대해 지원되지 않습니다.
JDK 8의 java.util.Optional은 required 속성(예: @RequestParam, @RequestHeader 등)이 있고 required=false에 해당하는 annotation과 함께 메서드 인수로 지원됩니다.
| Controller method argument | Description |
|---|---|
| WebRequest, NativeWebRequest | Servlet API를 직접 사용하지 않고 요청 매개변수, 요청 및 세션 속성에 대한 일반 액세스. |
| javax.servlet.ServletRequest, javax.servlet.ServletResponse | 특정 요청 또는 응답 유형 (예: ServletRequest, HttpServletRequest 또는 Spring의 MultipartRequest, MultipartHttpServletRequest)을 선택합니다. |
| javax.servlet.http.HttpSession | 세션의 존재를 강제합니다. 결과적으로 그러한 인수는 결코 null이 아닙니다. 세션 액세스는 스레드로부터 안전하지 않습니다. 여러 요청이 세션에 동시에 액세스할 수 있는 경우 RequestMappingHandlerAdapter 인스턴스의 synchronizeOnSession 플래그를 true로 설정하는 것을 고려하십시오. |
| javax.servlet.http.PushBuilder | 프로그래밍 방식의 HTTP/2 리소스 푸시를 위한 Servlet 4.0 푸시 빌더 API. 클라이언트가 해당 HTTP/2 기능을 지원하지 않는 경우 Servlet 사양에 따라 주입된 PushBuilder 인스턴스가 null이 될 수 있습니다. |
| java.security.Principal | 현재 인증된 사용자 — 알려진 경우 특정 Principal 구현 클래스일 수 있습니다. 이 인수는 HttpServletRequest#getUserPrincipal을 통해 기본 resolution으로 폴백하기 전에 사용자 정의 resolver가 resolve할 수 있도록 annotation이 달린 경우, 즉시 resolve되지 않습니다. 예를 들어, Spring Security Authentication은 Principal을 구현하고 HttpServletRequest#getUserPrincipal을 통해 주입될 것입니다. 단, @AuthenticationPrincipal로 annotation을 달지 않는 경우에는 Authentication#getPrincipal을 통해 사용자 정의 Spring Security resolver에 의해 resolve됩니다. |
| HttpMethod | 요청의 HTTP 메서드 |
| java.util.Locale | 사용 가능한 가장 구체적인 LocaleResolver에 의해 결정되는 현재 요청 로케일(사실상 구성된 LocaleResolver 또는 LocaleContextResolver). |
| java.util.TimeZone + java.time.ZoneId | LocaleContextResolver에 의해 결정되는 현재 요청과 관련된 시간대. |
| java.io.InputStream, java.io.Reader | Servlet API에 의해 노출된 원시 요청 본문에 대한 액세스. |
| java.io.OutputStream, java.io.Writer | Servlet API에 의해 노출되는 원시 응답 본문에 대한 액세스. |
| @PathVariable | URI 템플릿 변수에 액세스합니다. URI 패턴을 참조하십시오. |
| @MatrixVariable | URI 경로 세그먼트의 이름-값 쌍에 액세스합니다. Matrix Variables를 참조하십시오. |
| @RequestParam | 멀티파트 파일을 포함하여 서블릿 요청 매개변수에 액세스합니다. 매개변수 값은 선언된 메소드 인수 유형으로 변환됩니다. @RequestParam 및 Multipart를 참조하십시오. @RequestParam의 사용은 단순 매개변수 값의 선택 사항입니다. 이 표 끝에 있는 "Any other argument"를 참조하십시오. |
| @RequestHeader | 요청 헤더에 액세스합니다. 헤더 값은 선언된 메서드 인수 유형으로 변환됩니다. @RequestHeader를 참조하십시오. |
| @CookieValue | 쿠키에 대한 액세스. 쿠키 값은 선언된 메서드 인수 유형으로 변환됩니다. @CookieValue를 참조하십시오. |
| @RequestBody | HTTP 요청 본문에 액세스합니다. 본문 내용은 HttpMessageConverter 구현을 사용하여 선언된 메서드 인수 형식으로 변환됩니다. @RequestBody를 참조하십시오. |
HttpEntity<B> | 요청 헤더 및 본문에 액세스합니다. 본문은 HttpMessageConverter로 변환됩니다. HttpEntity를 참조하세요. |
| @RequestPart | multipart/form-data 요청의 파트에 액세스하려면 HttpMessageConverter를 사용하여 파트의 본문을 변환합니다. Multipart를 참조하십시오. |
| java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap | HTML 컨트롤러에서 사용되며 뷰 렌더링의 일부로 템플릿에 노출되는 모델에 액세스합니다. |
| RedirectAttributes | 리디렉션(즉, 쿼리 문자열에 추가) 시 사용할 속성과 리디렉션 후 요청이 있을 때까지 임시로 저장할 플래시 속성을 지정합니다. 리디렉션 속성 및 플래시 속성을 참조하십시오. |
| @ModelAttribute | 데이터 바인딩 및 유효성 검사가 적용된 모델의 기존 속성(존재하지 않는 경우 인스턴스화됨)에 액세스합니다. @ModelAttribute와 Model 및 DataBinder를 참조하십시오. @ModelAttribute 사용은 선택 사항입니다(예: 속성 설정). 이 표 끝에 있는 "Any other argument"를 참조하십시오. |
| Errors, BindingResult | 명령 객체(즉, @ModelAttribute 인수)에 대한 유효성 검사 및 데이터 바인딩 오류 또는 @RequestBody 또는 @RequestPart 인수 유효성 검사 오류에 대한 액세스. 검증된 메서드 인수 직후에 Errors 또는 BindingResult 인수를 선언해야 합니다. |
| SessionStatus + class-level @SessionAttributes | 양식 처리 완료로 표시하기 위해 클래스 수준 @SessionAttributes annotation을 통해 선언된 세션 속성 정리를 트리거합니다. 자세한 내용은 @SessionAttributes를 참조하세요. |
| UriComponentsBuilder | 현재 요청의 호스트, 포트, 체계, 컨텍스트 경로 및 서블릿 매핑의 리터럴 부분과 관련된 URL을 준비합니다. URI Links를 참조하십시오. |
| @SessionAttribute | 클래스 수준 @SessionAttributes 선언의 결과로 세션에 저장된 모델 속성과 달리 모든 세션 속성에 액세스합니다. 자세한 내용은 @SessionAttribute를 참조하세요. |
| @RequestAttribute | 요청 속성에 액세스합니다. 자세한 내용은 @RequestAttribute를 참조하세요. |
| Any other argument | 메소드 인수가 이 테이블의 이전 값과 일치하지 않고 단순 유형이면(BeanUtils#isSimpleProperty에 의해 결정된 대로 @RequestParam으로 해석되고, 그렇지 않으면 @ModelAttribute로 해석됩니다. |
다음 표에서는 지원되는 컨트롤러 메서드 반환 값을 설명합니다. 모든 반환 값에 대해 반응형 유형이 지원됩니다.
| Controller method return value | Description |
|---|---|
| @ResponseBody | 반환 값은 HttpMessageConverter 구현을 통해 변환되고 응답에 기록됩니다. @ResponseBody를 참조하십시오. |
HttpEntity<B>, ResponseEntity<B> | 전체 응답(HTTP 헤더 및 본문 포함)을 지정하는 반환 값은 HttpMessageConverter 구현을 통해 변환되어 응답에 기록됩니다. ResponseEntity를 참조하십시오. |
| HttpHeaders | 헤더가 있고 본문이 없는 응답을 반환합니다. |
| String | ViewResolver 구현으로 확인되고 암시적 모델 과 함께 사용되는 뷰 이름 - 명령 객체 및 @ModelAttribute 메서드를 통해 결정됩니다. 핸들러 메서드는 Model 인수를 선언하여 프로그래밍 방식으로 모델을 강화할 수도 있습니다(Explicit Registrations) 참조). |
| View | 암시적 모델 과 함께 렌더링에 사용할 View 인스턴스 - 명령 개체 및 @ModelAttribute 메서드를 통해 결정됩니다. 핸들러 메서드는 Model 인수를 선언하여 프로그래밍 방식으로 모델을 강화할 수도 있습니다(Explicit Registrations 참조). |
| java.util.Map, org.springframework.ui.Model | RequestToViewNameTranslator를 통해 암시적으로 결정된 뷰 이름을 사용하여 암시적 모델에 추가할 속성입니다. |
| @ModelAttribute | RequestToViewNameTranslator를 통해 암시적으로 결정된 뷰 이름을 사용하여 모델에 추가할 속성입니다. @ModelAttribute는 선택 사항입니다. 이 표 끝에 있는 "Any other return value"을 참조하십시오. |
| ModelAndView object | 사용할 뷰 및 모델 속성 및 선택적으로 response status |
| void | void 반환 유형(또는 null 반환 값)이 있는 메서드는 ServletResponse, OutputStream 인수 또는 @ResponseStatus annotation도 있는 경우, 응답을 완전히 처리한 것으로 간주됩니다. 컨트롤러가 긍정적인 ETag 또는 lastModified 타임스탬프 검사를 수행한 경우에도 마찬가지입니다(자세한 내용은 Controllers 참조). 위의 어느 것도 참이 아닌 경우 void 반환 유형은 REST 컨트롤러의 경우 "응답 본문 없음"을 나타내거나 HTML 컨트롤러의 경우 기본 보기 이름 선택을 나타낼 수도 있습니다. |
DeferredResult<V> | 예를 들어 일부 이벤트 또는 콜백의 결과로 스레드에서 비동기적으로 앞의 반환 값을 생성합니다. 비동기 요청 및 DeferredResult를 참조하십시오. |
Callable<V> | Spring MVC 관리 스레드에서 위의 반환 값을 비동기적으로 생성합니다. 비동기 요청 및 Callable을 참조하세요. |
ListenableFuture<V>, java.util.concurrent.CompletionStage<V>, java.util.concurrent.CompletableFuture<V> | 편의상 DeferredResult의 대안입니다(예: 기본 서비스가 그 중 하나를 반환하는 경우). |
| ResponseBodyEmitter, SseEmitter | HttpMessageConverter 구현을 사용하여 응답에 기록할 개체 스트림을 비동기적으로 내보냅니다. ResponseEntity의 본문으로도 지원됩니다. 비동기 요청 및 HTTP 스트리밍을 참조하세요. |
| StreamingResponseBody | 응답 OutputStream에 비동기적으로 씁니다. ResponseEntity의 본문으로도 지원됩니다. 비동기 요청 및 HTTP 스트리밍을 참조하세요. |
| Reactive types — Reactor, RxJava, or others through ReactiveAdapterRegistry | 리스트로 모은 다중 값 스트림(예: Flux, Observable)으로 DeferredResult의 대안입니다. 스트리밍 시나리오(예: text/event-stream, application/json+stream)의 경우, SseEmitter 및 ResponseBodyEmitter가 대신 사용됩니다. 여기서 ServletOutputStream blocking I/O는 Spring MVC 관리 스레드에서 수행되고 각 쓰기 완료에 대해 back pressure이 적용됩니다. . 비동기식 요청 및 Reactive Types을 참조하십시오. |
| Any other return value | 이 테이블의 이전 값과 일치하지 않고 String 또는 void인 모든 반환 값은 BeanUtils#isSimpleProperty에 의해 결정된 단순 유형이 아닌 경우, 뷰 이름으로 처리됩니다(RequestToViewNameTranslator를 통한 기본 뷰 이름 선택이 적용됨). 단순 유형인 값은 확인되지 않은 상태로 남아 있습니다. |
문자열 기반 요청 입력을 나타내는 주석이 달린 일부 컨트롤러 메서드 인수(예: @RequestParam, @RequestHeader, @PathVariable, @MatrixVariable 및 @CookieValue)는 인수가 문자열이 아닌 다른 것으로 선언된 경우, 유형 변환이 필요할 수 있습니다.
이러한 경우 구성한 converters에 따라 자동으로 형식 변환이 적용됩니다. 기본적으로 단순 유형(int, long, Date 등)이 지원됩니다. WebDataBinder(DataBinder 참조)를 통해 또는 FormattingConversionService에 Formatter를 등록하여 형식 변환을 사용자 지정할 수 있습니다. Spring Field Formatting을 참조하십시오.
유형 변환의 실제 문제는 빈 문자열 소스 값의 처리입니다. 이러한 값은 유형 변환의 결과로 null이 되면 누락된 것으로 처리됩니다. Long, UUID 및 기타 대상 유형의 경우일 수 있습니다. null 주입을 허용하려면 인수 annotation에 필수 플래그를 사용하거나 인수를 @Nullable로 선언하십시오.
5.3부터 null이 아닌 인수는 형식 변환 후에도 적용됩니다. 핸들러 메서드가 null 값도 허용하려는 경우 인수를 @Nullable로 선언하거나 해당 @RequestParam 등 annotation에서 required=false로 표시합니다. 이것은 5.3 업그레이드에서 발생하는 회귀에 대한 모범 사례이자 권장 솔루션입니다.
또는 예를 들어 구체적으로 처리할 수 있습니다. 필수 @PathVariable의 경우, 결과 MissingPathVariableException입니다. 변환 후 null 값은 비어 있는 원래 값으로 처리되므로 해당 Missing...예외 변형이 발생합니다.
RFC 3986은 경로 세그먼트의 이름-값 쌍에 대해 설명합니다. Spring MVC에서는 이것을 Tim Berners-Lee의 "old post"를 기반으로 "matrix variables"라고 부르지만, URI 경로 매개변수라고도 할 수 있습니다.
행렬 변수는 모든 경로 세그먼트에 나타날 수 있으며 각 변수는 세미콜론으로 구분되고 여러 값은 쉼표로 구분됩니다(예: /cars;color=red,green;year=2012). 반복되는 변수 이름을 통해 여러 값을 지정할 수도 있습니다(예: color=red;color=green;color=blue).
URL에 행렬 변수가 포함될 것으로 예상되는 경우 컨트롤러 메서드에 대한 요청 매핑은 URI 변수를 사용하여 해당 변수 내용을 마스킹하고 행렬 변수의 순서 및 존재 여부에 관계없이 요청이 성공적으로 일치될 수 있도록 해야 합니다. 다음 예제에서는 행렬 변수를 사용합니다.
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
모든 경로 세그먼트에 행렬 변수가 포함될 수 있다는 점을 감안할 때, 행렬 변수가 있을 것으로 예상되는 경로 변수를 명확하게 해야 하는 경우가 있습니다. 다음 예에서는 그렇게 하는 방법을 보여줍니다.
// GET /owners/42;q=11/pets/21;q=22
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {
// q1 == 11
// q2 == 22
}
행렬 변수는 다음 예제와 같이 선택 사항으로 정의되고 기본값이 지정될 수 있습니다.
// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
// q == 1
}
모든 행렬 변수를 가져오려면 다음 예제와 같이 MultiValueMap을 사용할 수 있습니다.
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap<String, String> matrixVars,
@MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}
행렬 변수의 사용을 활성화해야 합니다. MVC Java 구성에서 Path Matching을 통해 removeSemicolonContent=false로 UrlPathHelper를 설정해야 합니다. MVC XML 네임스페이스에서 <mvc:annotation-driven enable-matrix-variables="true"/>을 설정할 수 있습니다.
@RequestParam annotation을 사용하여 서블릿 요청 매개변수(즉, 쿼리 매개변수 또는 양식 데이터)를 컨트롤러의 메소드 인수에 바인딩할 수 있습니다.
다음 예에서는 그렇게 하는 방법을 보여줍니다.
@Controller
@RequestMapping("/pets")
public class EditPetForm {
// ...
@GetMapping
public String setupForm(@RequestParam("petId") int petId, Model model) { // (1)
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
}
(1) @RequestParam을 사용하여 petId를 바인딩합니다.
기본적으로 이 annotation을 사용하는 메소드 매개변수는 필수이지만 @RequestParam annotation의 필수 플래그를 false로 설정하거나 java.util.Optional 래퍼로 인수를 선언하여 메소드 매개변수를 선택사항으로 지정할 수 있습니다.
대상 메소드 매개변수 유형이 String이 아닌 경우 유형 변환이 자동으로 적용됩니다. Type Conversion을 참조하십시오.
인수 유형을 배열 또는 목록으로 선언하면 동일한 매개변수 이름에 대한 여러 매개변수 값을 확인할 수 있습니다.
@RequestParam annotation이 annotation에 지정된 매개변수 이름 없이 Map<String, String> 또는 MultiValueMap<String, String>으로 선언되면 맵은 지정된 각 매개변수 이름에 대한 요청 매개변수 값으로 채워집니다.
@RequestParam의 사용은 선택 사항입니다(예: 속성 설정). 기본적으로 단순 값 유형(BeanUtils#isSimpleProperty에 의해 결정됨)이고 다른 argument resolver에 의해 resolve되지 않는 모든 인수는 @RequestParam으로 annotation이 달린 것처럼 처리됩니다.
@RequestHeader annotation을 사용하여 요청 헤더를 컨트롤러의 메서드 인수에 바인딩할 수 있습니다.
헤더가 있는 다음 요청을 고려하십시오.
Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
다음 예에서는 Accept-Encoding 및 Keep-Alive 헤더 값을 가져옵니다.
@GetMapping("/demo")
public void handle(
@RequestHeader("Accept-Encoding") String encoding, // (1)
@RequestHeader("Keep-Alive") long keepAlive) { // (2)
//...
}
(1) Accept-Encoding 헤더의 값을 가져옵니다.
(2) Keep-Alive 헤더의 값을 가져옵니다.
대상 메소드 매개변수 유형이 String이 아닌 경우 유형 변환이 자동으로 적용됩니다. Type Conversion을 참조하십시오.
@RequestHeader annotation이 Map<String, String>, MultiValueMap<String, String> 또는 HttpHeaders 인수에 사용되는 경우 맵은 모든 헤더 값으로 채워집니다.
기본 제공 지원은 쉼표로 구분된 문자열을 형식 변환 시스템에 알려진 문자열 또는 기타 형식의 배열이나 컬렉션으로 변환하는 데 사용할 수 있습니다. 예를 들어 @RequestHeader("Accept") annotation이 달린 메서드 매개변수는 String 유형일 수 있지만 String[] 또는 List
<String>일 수도 있습니다.
@CookieValue annotation을 사용하여 HTTP 쿠키 값을 컨트롤러의 메서드 인수에 바인딩할 수 있습니다.
다음 쿠키가 있는 요청을 고려하십시오.
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
다음 예는 쿠키 값을 가져오는 방법을 보여줍니다.
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { // (1)
//...
}
(1) JSESSIONID 쿠키의 값을 가져옵니다.
대상 메소드 매개변수 유형이 String이 아닌 경우, 유형 변환이 자동으로 적용됩니다. Type Conversion을 참조하십시오.
메소드 인수에 @ModelAttribute annotation을 사용하여 모델의 속성에 액세스하거나 존재하지 않는 경우, 인스턴스화할 수 있습니다. 또한 모델 속성은 이름이 필드 이름과 일치하는 HTTP 서블릿 요청 매개변수의 값으로 오버레이됩니다. 이를 데이터 바인딩이라고 하며 개별 쿼리 매개변수와 양식 필드를 구문 분석하고 변환하는 작업을 수행하지 않아도 됩니다. 다음 예에서는 그렇게 하는 방법을 보여줍니다.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
위의 Pet 인스턴스는 다음 방법 중 하나로 소싱됩니다.
@ModelAttribute 메소드에 의해 추가되었을 수 있는 모델에서 검색됩니다.
모델 속성이 클래스 수준 @SessionAttributes 주석에 나열된 경우 HTTP 세션에서 검색됩니다.
모델 속성 이름이 경로 변수 또는 요청 매개변수와 같은 요청 값의 이름과 일치하는 Converter를 통해 가져옵니다(다음 예 참조).
기본 생성자를 사용하여 인스턴스화됩니다.
서블릿 요청 매개변수와 일치하는 인수가 있는 "기본 생성자"를 통해 인스턴스화됩니다. 인수 이름은 JavaBeans @ConstructorProperties를 통해 또는 바이트코드에서 런타임에 유지되는 매개변수 이름을 통해 결정됩니다.
@ModelAttribute Method를 사용하여 제공하거나 프레임워크에 의존하여 모델 속성을 생성하는 것의 한 가지 대안은 Converter<String, T>를 사용하여 인스턴스를 제공하는 것입니다. 모델 속성 이름이 경로 변수나 요청 매개변수와 같은 요청 값의 이름과 일치하고, String에서 모델 속성 유형으로의 Converter가 있는 경우에 적용됩니다. 다음 예에서 모델 속성 이름은 URI 경로 변수 account과 일치하는 account이고 데이터 저장소에서 Account을 로드할 수 있는 등록된 Converter<String, Account>가 있습니다.
@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) {
// ...
}
모델 속성 인스턴스를 얻은 후 데이터 바인딩이 적용됩니다. WebDataBinder 클래스는 서블릿 요청 매개변수 이름(쿼리 매개변수 및 양식 필드)을 대상 Object의 필드 이름과 일치시킵니다. 필요한 경우 유형 변환이 적용된 후 일치하는 필드가 채워집니다. 데이터 바인딩(및 유효성 검사)에 대한 자세한 내용은 Validation를 참조하세요. 데이터 바인딩 사용자 지정에 대한 자세한 내용은 DataBinder를 참조하세요.
데이터 바인딩으로 인해 오류가 발생할 수 있습니다. 기본적으로 BindException이 발생합니다. 그러나 컨트롤러 메서드에서 이러한 오류를 확인하기 위해 다음 예제와 같이 @ModelAttribute 바로 옆에 BindingResult 인수를 추가할 수 있습니다.
데이터 바인딩으로 인해 오류가 발생할 수 있습니다. 기본적으로 BindException이 발생합니다. 그러나 컨트롤러 메서드에서 이러한 오류를 확인하기 위해 다음 예제와 같이 @ModelAttribute 바로 옆에 BindingResult 인수를 추가할 수 있습니다.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { // (1)
if (result.hasErrors()) {
return "petForm";
}
// ...
}
(1) @ModelAttribute 옆에 BindingResult 추가
경우에 따라 데이터 바인딩 없이 모델 속성에 액세스할 수 있습니다. 이러한 경우 Model을 컨트롤러에 삽입하고 직접 액세스하거나 다음 예제와 같이 @ModelAttribute(binding=false)를 설정할 수 있습니다.
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@PostMapping("update")
public String update(@Valid AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) { // (1)
// ...
}
(1) @ModelAttribute(binding=false) 설정.
javax.validation.Valid 어노테이션 또는 Spring의 @Validated 어노테이션(Bean Validation 및 Spring validation)을 추가하여 데이터 바인딩 후 유효성 검증을 자동으로 적용할 수 있습니다. 다음 예에서는 그렇게 하는 방법을 보여줍니다.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { // (1)
if (result.hasErrors()) {
return "petForm";
}
// ...
}
(1) Pet 인스턴스의 유효성을 검사합니다.
@ModelAttribute 사용은 선택 사항입니다(예: 속성 설정). 기본적으로 단순 값 유형이 아니고(BeanUtils#isSimpleProperty에 의해 결정됨) 다른 argument resolver에 의해 해결되지 않는 모든 인수는 @ModelAttribute로 annotation이 달린 것처럼 처리됩니다.
@SessionAttributes는 요청 사이의 HTTP 서블릿 세션에 모델 속성을 저장하는 데 사용됩니다. 특정 컨트롤러에서 사용하는 세션 속성을 선언하는 유형 수준 annotation입니다. 여기에는 일반적으로 액세스할 후속 요청을 위해 세션에 투명하게 저장해야 하는 모델 속성의 이름 또는 모델 속성 유형이 나열됩니다.
다음 예제에서는 @SessionAttributes annotation을 사용합니다.
@Controller
@SessionAttributes("pet") // (1)
public class EditPetForm {
// ...
}
(1) @SessionAttributes annotation 사용.
첫 번째 요청에서 이름이 pet인 모델 속성이 모델에 추가되면 자동으로 HTTP 서블릿 세션으로 승격되어 저장됩니다. 다음 예제와 같이 다른 컨트롤러 메서드가 SessionStatus 메서드 인수를 사용하여 저장소를 지울 때까지 그대로 유지됩니다.
@Controller
@SessionAttributes("pet") // (1)
public class EditPetForm {
// ...
@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete(); // (2)
// ...
}
}
(1) Servlet 세션에 Pet 값을 저장합니다.
(2) Servlet 세션에서 Pet 값을 지웁니다.
전역적으로 관리되는 기존 세션 속성에 액세스해야 하는 경우(즉, 컨트롤러 외부 — 필터에 의해) 존재하거나 존재하지 않을 수 있는 경우, 다음과 같이 메소드 매개변수에 @SessionAttribute annotation을 사용할 수 있습니다. 다음 예는 다음을 보여줍니다.
@RequestMapping("/")
public String handle(@SessionAttribute User user) { // (1)
// ...
}
(1) @SessionAttribute annotation 사용.
세션 속성을 추가하거나 제거해야 하는 사용 사례의 경우 컨트롤러 메소드에 org.springframework.web.context.request.WebRequest 또는 javax.servlet.http.HttpSession을 삽입하는 것을 고려하십시오.
컨트롤러 워크플로의 일부로 세션에 모델 속성을 임시로 저장하려면 @SessionAttributes에 설명된 대로 @SessionAttributes를 사용하는 것이 좋습니다.
@SessionAttribute와 유사하게 @RequestAttribute 어노테이션을 사용하여 이전에 생성된 기존 요청 속성(예: Servlet Filter 또는 HandlerInterceptor에 의해)에 액세스할 수 있습니다.
@GetMapping("/")
public String handle(@RequestAttribute Client client) { // (1)
// ...
}
(1) @RequestAttribute annotation 사용.
기본적으로 모든 모델 속성은 리디렉션 URL에서 URI 템플릿 변수로 노출되는 것으로 간주됩니다. 나머지 속성 중 기본 유형 또는 기본 유형의 컬렉션 또는 배열인 속성은 자동으로 쿼리 매개변수로 추가됩니다.
모델 인스턴스가 리디렉션을 위해 특별히 준비된 경우 기본 유형 속성을 쿼리 매개변수로 추가하면 원하는 결과가 될 수 있습니다. 그러나 annotation이 달린 컨트롤러에서 모델은 렌더링 목적으로 추가된 추가 속성(예: 드롭다운 필드 값)을 포함할 수 있습니다. 이러한 속성이 URL에 나타날 가능성을 피하기 위해 @RequestMapping 메서드는 RedirectAttributes 유형의 인수를 선언하고 이를 사용하여 RedirectView에서 사용할 수 있도록 정확한 속성을 지정할 수 있습니다. 메서드가 리디렉션하는 경우, RedirectAttributes의 콘텐츠가 사용됩니다. 그렇지 않으면 모델의 내용이 사용됩니다.
RequestMappingHandlerAdapter는 ignoreDefaultModelOnRedirect라는 플래그를 제공합니다. 이 플래그를 사용하여 컨트롤러 메서드가 리디렉션되는 경우 기본 Model의 콘텐츠가 사용되지 않아야 함을 나타낼 수 있습니다. 대신 컨트롤러 메서드는 RedirectAttributes 유형의 속성을 선언해야 하며, 그렇게 하지 않으면 속성이 RedirectView에 전달되어서는 안 됩니다. MVC 네임스페이스와 MVC Java 구성 모두 이전 버전과의 호환성을 유지하기 위해 이 플래그를 false로 설정합니다. 그러나 새 응용 프로그램의 경우, true로 설정하는 것이 좋습니다.
현재 요청의 URI 템플릿 변수는 리디렉션 URL을 확장할 때 자동으로 사용 가능하게 되며 Model 또는 RedirectAttributes를 통해 명시적으로 추가할 필요가 없습니다. 다음 예는 리디렉션을 정의하는 방법을 보여줍니다.
@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}
데이터를 리디렉션 대상에 전달하는 또 다른 방법은 플래시 속성을 사용하는 것입니다. 다른 리디렉션 속성과 달리 플래시 속성은 HTTP 세션에 저장되므로 URL에 표시되지 않습니다. 자세한 내용은 Flash Attributes을 참조하십시오.
Flash 속성은 한 요청이 다른 요청에서 사용할 속성을 저장하는 방법을 제공합니다. 이는 리디렉션 (예: Post-Redirect-Get 패턴)을 리디렉션할 때 가장 일반적으로 필요합니다. Flash 속성은 리디렉션 후 요청에 사용할 수 있도록 리디렉션 전에(일반적으로 세션에) 임시로 저장되고 즉시 제거됩니다.
Spring MVC에는 플래시 속성을 지원하는 두 가지 주요 추상화가 있습니다. FlashMap은 플래시 속성을 유지하는 데 사용되는 반면, FlashMapManager는 FlashMap 인스턴스를 저장, 검색 및 관리하는 데 사용됩니다.
Flash 속성 지원은 항상 "켜짐"이며 명시적으로 활성화할 필요가 없습니다. 그러나 사용하지 않으면 HTTP 세션이 생성되지 않습니다. 각 요청에는 이전 요청(있는 경우)에서 전달된 속성이 있는 "입력" FlashMap과 후속 요청을 위해 저장할 속성이 있는 "출력" FlashMap이 있습니다. 두 FlashMap 인스턴스는 RequestContextUtils의 정적 메서드를 통해 Spring MVC의 모든 위치에서 액세스할 수 있습니다.
Annotation이 달린 컨트롤러는 일반적으로 FlashMap과 직접 작동할 필요가 없습니다. 대신 @RequestMapping 메서드는 RedirectAttributes 유형의 인수를 수락하고 이를 사용하여 리디렉션 시나리오에 대한 플래시 속성을 추가할 수 있습니다. RedirectAttributes를 통해 추가된 Flash 속성은 "출력" FlashMap에 자동으로 전파됩니다. 마찬가지로 리디렉션 후 "입력" FlashMap의 속성이 대상 URL을 제공하는 컨트롤러의 Model에 자동으로 추가됩니다.
플래시 속성에 대한 요청 일치
플래시 속성의 개념은 다른 많은 웹 프레임워크에 존재하며 때때로 동시성 문제에 노출되는 것으로 입증되었습니다. 이는 정의에 따라 플래시 속성이 다음 요청까지 저장되어야 하기 때문입니다. 그러나 바로 "다음" 요청은 의도한 수신자가 아니라 또 다른 비동기 요청(예: 폴링 또는 리소스 요청)일 수 있습니다. 이 경우 플래시 속성이 너무 일찍 제거됩니다.
이러한 문제의 가능성을 줄이기 위해 RedirectView는 대상 리디렉션 URL의 경로 및 쿼리 매개변수로 FlashMap 인스턴스를 자동으로 "스탬프"합니다. 차례로 기본 FlashMapManager는 "입력" FlashMap을 조회할 때, 해당 정보를 들어오는 요청과 일치시킵니다.
이렇게 하면 동시성 문제의 가능성이 완전히 제거되지는 않지만 리디렉션 URL에서 이미 사용할 수 있는 정보로 인해 문제가 크게 줄어듭니다. 따라서 주로 리디렉션 시나리오에 플래시 속성을 사용하는 것이 좋습니다.
MultipartResolver가 활성화되면 multipart/form-data가 있는 POST 요청의 내용이 구문 분석되고 일반 요청 매개변수로 액세스할 수 있습니다. 다음 예는 하나의 일반 양식 필드와 하나의 업로드된 파일에 액세스합니다.
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
인수 유형을 List<MultipartFile>로 선언하면 동일한 매개변수 이름에 대해 여러 파일을 확인할 수 있습니다.
@RequestParam annotation이 annotation에 지정된 매개변수 이름 없이 Map<String, MultipartFile> 또는 MultiValueMap<String, MultipartFile>로 선언되면 맵은 지정된 각 매개변수 이름에 대한 멀티파트 파일로 채워집니다.
Servlet 3.0 멀티파트 파싱을 사용하면 Spring의
MultipartFile대신javax.servlet.http.Part를 메소드 인수 또는 컬렉션 값 유형으로 선언할 수도 있습니다.
command object에 대한 데이터 바인딩의 일부로 멀티파트 콘텐츠를 사용할 수도 있습니다. 예를 들어, 이전 예제의 양식 필드와 파일은 다음 예제와 같이 양식 개체의 필드일 수 있습니다.
class MyForm {
private String name;
private MultipartFile file;
// ...
}
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
if (!form.getFile().isEmpty()) {
byte[] bytes = form.getFile().getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
RESTful 서비스 시나리오에서 브라우저가 아닌 클라이언트에서 멀티파트 요청을 제출할 수도 있습니다. 다음 예는 JSON이 포함된 파일을 보여줍니다.
POST /someUrl
Content-Type: multipart/mixed
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{
"name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...
@RequestParam을 문자열로 사용하여 "메타 데이터" 부분에 액세스할 수 있지만 아마도 JSON에서 역직렬화되기를 원할 것입니다(@RequestBody와 유사). @RequestPart annotation을 사용하여 HttpMessageConverter로 변환한 후 멀티파트에 액세스합니다.
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
@RequestPart를 javax.validation.Valid와 함께 사용하거나 Spring의 @Validated 주석을 사용할 수 있습니다. 둘 다 Standard Bean Validation이 적용되도록 합니다. 기본적으로 유효성 검사 오류는 400(BAD_REQUEST) 응답으로 바뀌는 MethodArgumentNotValidException을 발생시킵니다. 또는 다음 예제와 같이 Errors 또는 BindingResult 인수를 통해 컨트롤러 내에서 로컬로 유효성 검사 오류를 처리할 수 있습니다.
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
@RequestBody annotation을 사용하여 요청 본문을 읽고 HttpMessageConverter를 통해 Object로 역직렬화하도록 할 수 있습니다. 다음 예제에서는 @RequestBody 인수를 사용합니다.
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
MVC Config의 Message Converters 옵션을 사용하여 메시지 변환을 구성하거나 사용자 지정할 수 있습니다.
@RequestBody를 javax.validation.Valid 또는 Spring의 @Validated 주석과 함께 사용할 수 있으며 둘 다 Standard Bean Validation이 적용되도록 합니다. 기본적으로 유효성 검사 오류는 400(BAD_REQUEST) 응답으로 바뀌는 MethodArgumentNotValidException을 발생시킵니다. 또는 다음 예제와 같이 Errors 또는 BindingResult 인수를 통해 컨트롤러 내에서 로컬로 유효성 검사 오류를 처리할 수 있습니다.
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
// ...
}
HttpEntity는 @RequestBody를 사용하는 것과 거의 동일하지만 요청 헤더와 본문을 노출하는 컨테이너 개체를 기반으로 합니다. 다음 목록은 예를 보여줍니다.
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
메서드에 @ResponseBody annotation을 사용하여 HttpMessageConverter를 통해 응답 본문에 반환을 직렬화할 수 있습니다. 다음 목록은 예를 보여줍니다.
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
@ResponseBody는 클래스 수준에서도 지원되며 이 경우 모든 컨트롤러 메서드에서 상속됩니다. 이것은 @RestController의 효과로, @Controller와 @ResponseBody로 표시된 메타 annotation에 불과합니다.
Reactive Types과 함께 @ResponseBody를 사용할 수 있습니다. 자세한 내용은 비동기 요청 및 Reactive Types을 참조하세요.
MVC Config의 Message Converters 옵션을 사용하여 메시지 변환을 구성하거나 사용자 지정할 수 있습니다.
@ResponseBody 메소드를 JSON 직렬화 보기와 결합할 수 있습니다. 자세한 내용은 Jackson JSON을 참조하세요.
ResponseEntity는 @ResponseBody와 비슷하지만 상태와 헤더가 있습니다. 예를 들어:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).build(body);
}
Spring MVC는 ResponseEntity를 비동기식으로 생성하기 위해 단일 값 reactive type을 사용하거나 본문에 대해 단일 및 다중 값 반응 유형을 사용하는 것을 지원합니다. 이렇게 하면 다음 유형의 비동기 응답이 허용됩니다.
ResponseEntity<Mono<T>> 또는 ResponseEntity<Flux<T>>는 응답 상태와 헤더를 즉시 알리고 본문은 나중에 비동기적으로 제공합니다. 본문이 0..1개의 값으로 구성된 경우 Mono를 사용하고 여러 값을 생성할 수 있는 경우 Flux를 사용합니다.
Mono<ResponseEntity<T>>는 응답 상태, 헤더 및 본문을 나중에 비동기적으로 모두 제공합니다. 이렇게 하면 비동기 요청 처리의 결과에 따라 응답 상태와 헤더가 달라질 수 있습니다.
Spring은 Jackson JSON 라이브러리에 대한 지원을 제공합니다.
Spring MVC는 Object에 있는 모든 필드의 하위 집합만 렌더링할 수 있는 Jackson’s Serialization Views에 대한 내장 지원을 제공합니다. @ResponseBody 또는 ResponseEntity 컨트롤러 메서드와 함께 사용하려면 다음 예제와 같이 Jackson의 @JsonView annotation을 사용하여 직렬화 뷰 클래스를 활성화할 수 있습니다.
@RestController
public class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView.class)
public User getUser() {
return new User("eric", "7!jd#h23");
}
}
public class User {
public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
@JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}
@JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}
@JsonView는 뷰 클래스의 배열을 허용하지만 컨트롤러 메서드당 하나만 지정할 수 있습니다. 여러 뷰를 활성화해야 하는 경우 복합 인터페이스를 사용할 수 있습니다.
프로그래밍 방식으로 위의 작업을 수행하려면 @JsonView annotation을 선언하는 대신 반환 값을 MappingJacksonValue로 래핑하고 이를 사용하여 직렬화 뷰를 제공합니다.
@RestController
public class UserController {
@GetMapping("/user")
public MappingJacksonValue getUser() {
User user = new User("eric", "7!jd#h23");
MappingJacksonValue value = new MappingJacksonValue(user);
value.setSerializationView(User.WithoutPasswordView.class);
return value;
}
}
view resolution에 의존하는 컨트롤러의 경우, 다음 예제와 같이 직렬화 뷰 클래스를 모델에 추가할 수 있습니다.
@Controller
public class UserController extends AbstractController {
@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", new User("eric", "7!jd#h23"));
model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
return "userView";
}
}
@ModelAttribute annotation을 사용할 수 있습니다.
@RequestMapping 메서드의 메서드 인수에서 모델에서 Object를 만들거나 액세스하고 WebDataBinder를 통해 요청에 바인딩합니다.
@RequestMapping 메서드 호출 전에 모델을 초기화하는 데 도움이 되는 @Controller 또는 @ControllerAdvice 클래스의 메서드 수준 annotation.
@RequestMapping 메서드에서 반환 값을 표시하는 것은 모델 속성입니다.
이 섹션에서는 @ModelAttribute 메서드 — 이전 목록의 두 번째 항목에 대해 설명합니다. 컨트롤러에는 @ModelAttribute 메서드가 여러 개 있을 수 있습니다. 이러한 모든 메서드는 동일한 컨트롤러의 @RequestMapping 메서드보다 먼저 호출됩니다. @ModelAttribute 메서드는 @ControllerAdvice를 통해 컨트롤러 간에 공유할 수도 있습니다. 자세한 내용은 컨트롤러 조언 섹션을 참조하십시오.
@ModelAttribute 메서드에는 유연한 메서드 서명이 있습니다. @ModelAttribute 자체 또는 요청 본문과 관련된 것을 제외하고 @RequestMapping 메서드와 동일한 인수를 많이 지원합니다.
다음 예제에서는 @ModelAttribute 메서드를 보여줍니다.
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
model.addAttribute(accountRepository.findAccount(number));
// add more ...
}
다음 예에서는 속성을 하나만 추가합니다.
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountRepository.findAccount(number);
}
이름이 명시적으로 지정되지 않은 경우 규칙에 대한 javadoc Convention에 설명된 대로
Objecttype을 기반으로 기본 이름이 선택됩니다. 오버로드된addAttribute메서드를 사용하거나@ModelAttribute의name속성(반환 값의 경우)을 통해 항상 명시적 이름을 할당할 수 있습니다.
@ModelAttribute를 @RequestMapping 메서드의 메서드 수준 annotation으로 사용할 수도 있습니다. 이 경우, @RequestMapping 메서드의 반환 값은 모델 속성으로 해석됩니다. 반환 값이 보기 이름으로 해석되는 String이 아닌 한 HTML 컨트롤러의 기본 동작이므로 일반적으로 필요하지 않습니다. @ModelAttribute는 다음 예제와 같이 모델 속성 이름을 사용자 지정할 수도 있습니다.
@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
public Account handle() {
// ...
return account;
}
@Controller 또는 @ControllerAdvice 클래스는 WebDataBinder의 인스턴스를 초기화하는 @InitBinder 메서드를 가질 수 있으며, 차례로 다음을 수행할 수 있습니다.
요청 매개변수(즉, 양식 또는 쿼리 데이터)를 모델 개체에 바인딩합니다.
문자열 기반 요청 값(요청 매개변수, 경로 변수, 헤더, 쿠키 등)을 컨트롤러 메서드 인수의 대상 유형으로 변환합니다.
HTML 양식을 렌더링할 때 모델 개체 값의 형식을 String 값으로 지정합니다.
@InitBinder 메소드는 컨트롤러별 java.beans.PropertyEditor 또는 Spring Converter 및 Formatter 구성요소를 등록할 수 있습니다. 또한 MVC 구성을 사용하여 전역적으로 공유되는 FormattingConversionService에 Converter 및 Formatter 유형을 등록할 수 있습니다.
@InitBinder 메서드는 @ModelAttribute(명령 객체) 인수를 제외하고 @RequestMapping 메서드가 수행하는 것과 동일한 많은 인수를 지원합니다. 일반적으로 WebDataBinder 인수(등록용)와 void 반환 값으로 선언됩니다. 다음 목록은 예를 보여줍니다.
@Controller
public class FormController {
@InitBinder //(1)
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
// ...
}
(1) @InitBinder 메서드 정의
또는 공유 FormattingConversionService를 통해 Formatter 기반 설정을 사용하는 경우 다음 예제와 같이 동일한 접근 방식을 재사용하고 컨트롤러별 Formatter 구현을 등록할 수 있습니다.
@Controller
public class FormController {
@InitBinder (1)
protected void initBinder(WebDataBinder binder) {
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
// ...
}
(1) 사용자 정의 포맷터에서 @InitBinder 메소드 정의.
@Controller 및 @ControllerAdvice 클래스는 다음 예제와 같이 컨트롤러 메서드의 예외를 처리하기 위해 @ExceptionHandler 메서드를 가질 수 있습니다.
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
예외는 전파되는 최상위 예외(예: 직접 IOException 발생) 또는 래퍼 예외 내의 중첩 원인(예: IllegalStateException 내부에 래핑된 IOException)과 일치할 수 있습니다. 5.3에서는 임의의 원인 수준에서 일치할 수 있지만 이전에는 즉각적인 원인만 고려되었습니다.
일치하는 예외 유형의 경우 앞의 예와 같이 대상 예외를 메서드 인수로 선언하는 것이 좋습니다. 여러 예외 방법이 일치하는 경우 일반적으로 원인 예외 일치보다 루트 예외 일치가 선호됩니다. 보다 구체적으로 ExceptionDepthComparator는 throw된 예외 유형의 깊이를 기반으로 예외를 정렬하는 데 사용됩니다.
또는 다음 예제와 같이 annotation 선언은 일치하도록 예외 유형을 좁힐 수 있습니다.
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
다음 예제와 같이 매우 일반적인 인수 서명과 함께 특정 예외 유형 목록을 사용할 수도 있습니다.
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
루트 와 원인 예외 일치 간의 구별로 놀라실 수 있습니다.
이전에 표시된 IOException 변형에서 메서드는 일반적으로 실제 FileSystemException 또는 RemoteException 인스턴스를 인수로 사용하여 호출됩니다. 둘 다 IOException에서 확장되기 때문입니다. 그러나 일치하는 예외가 래퍼 예외 내에서 전파되고 그 자체가 IOException인 경우 전달된 예외 인스턴스는 해당 래퍼 예외입니다.
이 동작은 handle(Exception) 변형에서 훨씬 더 간단합니다. 이것은 항상 래핑 시나리오에서 래퍼 예외와 함께 호출되며 이 경우 실제로 일치하는 예외는 ex.getCause()를 통해 찾을 수 있습니다. 전달된 예외는 최상위 예외로 throw된 경우에만 실제 FileSystemException 또는 RemoteException 인스턴스입니다.
일반적으로 인수 서명에서 가능한 한 구체적으로 작성하여 루트 예외 유형과 원인 예외 유형 간의 불일치 가능성을 줄이는 것이 좋습니다. 다중 일치 메소드를 개별 @ExceptionHandler 메소드로 분리하는 것을 고려하십시오. 각 메소드는 서명을 통해 단일 특정 예외 유형과 일치합니다.
다중 @ControllerAdvice 배열에서는 해당 순서로 우선 순위가 지정된 @ControllerAdvice에 대한 기본 루트 예외 매핑을 선언하는 것이 좋습니다. 루트 예외 일치가 원인보다 선호되지만 이는 지정된 컨트롤러 또는 @ControllerAdvice 클래스의 메서드 간에 정의됩니다. 이는 우선순위가 더 높은 @ControllerAdvice Bean에 대한 원인 일치가 우선순위가 낮은 @ControllerAdvice Bean에 대한 모든 일치(예: 루트)보다 선호됨을 의미합니다.
마지막으로 @ExceptionHandler 메소드 구현은 주어진 예외 인스턴스를 원래 형태로 다시 던져서 처리하지 않도록 선택할 수 있습니다. 이는 루트 수준 일치 또는 정적으로 결정할 수 없는 특정 컨텍스트 내의 일치에만 관심이 있는 시나리오에서 유용합니다. 주어진 @ExceptionHandler 메소드가 처음부터 일치하지 않았을 것처럼 다시 throw된 예외는 나머지 해결 체인을 통해 전파됩니다.
Spring MVC에서 @ExceptionHandler 메소드에 대한 지원은 DispatcherServlet 레벨인 HandlerExceptionResolver 메커니즘에서 빌드됩니다.
@ExceptionHandler 메서드는 다음 인수를 지원합니다.
| Method arguments | Description |
|---|---|
| Exception type | 발생한 예외에 대한 액세스용입니다. |
| HandlerMethod | 예외를 발생시킨 컨트롤러 메서드에 액세스합니다. |
| WebRequest, NativeWebRequest | Servlet API를 직접 사용하지 않고 요청 매개변수와 요청 및 세션 속성에 대한 일반 액세스. |
| javax.servlet.ServletRequest, javax.servlet.ServletResponse | 특정 요청 또는 응답 유형(예: ServletRequest 또는 HttpServletRequest 또는 Spring의 MultipartRequest 또는 MultipartHttpServletRequest)을 선택합니다. |
| javax.servlet.http.HttpSession | 세션의 존재를 강제합니다. 결과적으로 그러한 인수는 결코 null이 아닙니다. 세션 액세스는 스레드로부터 안전하지 않습니다. 여러 요청이 세션에 동시에 액세스할 수 있는 경우 RequestMappingHandlerAdapter 인스턴스의 synchronizeOnSession 플래그를 true로 설정하는 것을 고려하십시오. |
| java.security.Principal | 현재 인증된 사용자 — 알려진 경우 특정 Principal 구현 클래스일 수 있습니다. |
| HttpMethod | 요청의 HTTP 메서드입니다. |
| java.util.Locale | 사용 가능한 가장 구체적인 LocaleResolver에 의해 결정되는 현재 요청 로케일 —실제로 구성된 LocaleResolver 또는 LocaleContextResolver. |
| java.util.TimeZone, java.time.ZoneId | LocaleContextResolver에 의해 결정되는 현재 요청과 관련된 시간대. |
| java.io.OutputStream, java.io.Writer | Servlet API에 의해 노출되는 원시 응답 본문에 대한 액세스용입니다. |
| java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap | 오류 응답을 위해 모델에 액세스합니다. 항상 비어 있습니다. |
| RedirectAttributes | 리다이렉트 — (쿼리 문자열에 추가됨)의 경우 사용할 속성과 리다이렉션 후 요청까지 일시적으로 저장할 플래시 속성을 지정합니다. 리디렉션 속성 및 플래시 속성을 참조하십시오. |
| @SessionAttribute | 클래스 수준 @SessionAttributes 선언의 결과로 세션에 저장된 모델 속성과 달리 모든 세션 속성에 액세스합니다. 자세한 내용은 @SessionAttribute를 참조하세요. |
| @RequestAttribute | 요청 속성에 액세스합니다. 자세한 내용은 @RequestAttribute를 참조하세요. |
@ExceptionHandler 메서드는 다음 반환 값을 지원합니다.
| Return value | Description |
|---|---|
| @ResponseBody | 반환 값은 HttpMessageConverter 인스턴스를 통해 변환되고 응답에 기록됩니다. @ResponseBody를 참조하십시오. |
HttpEntity<B>, ResponseEntity<B> | 반환 값은 전체 응답(HTTP 헤더 및 본문 포함)이 HttpMessageConverter 인스턴스를 통해 변환되고 응답에 기록되도록 지정합니다. ResponseEntity를 참조하십시오. |
| String | ViewResolver 구현으로 확인되고 암시적 모델과 함께 사용되는 뷰 이름 - 명령 개체 및 @ModelAttribute 메서드를 통해 결정됩니다. 핸들러 메서드는 Model 인수(앞서 설명)를 선언하여 프로그래밍 방식으로 모델을 보강할 수도 있습니다. |
| View | 암시적 모델 과 함께 렌더링하는 데 사용할 View 인스턴스 - 명령 개체 및 @ModelAttribute 메서드를 통해 결정됩니다. 핸들러 메서드는 Model 인수(앞서 설명)를 선언하여 프로그래밍 방식으로 모델을 강화할 수도 있습니다. |
| java.util.Map, org.springframework.ui.Model | RequestToViewNameTranslator를 통해 암시적으로 결정된 뷰 이름을 사용하여 암시적 모델에 추가할 속성입니다. |
| @ModelAttribute | RequestToViewNameTranslator를 통해 암시적으로 결정된 뷰 이름을 사용하여 모델에 추가할 속성입니다. @ModelAttribute는 선택 사항입니다. 이 표 끝에 있는 "Any other return value"을 참조하십시오. |
| ModelAndView object | 사용할 뷰 및 모델 속성 및 선택적으로 response status입니다. |
| void | void 반환 유형(또는 null 반환 값)이 있는 메서드는 ServletResponse, OutputStream 인수 또는 @ResponseStatus annotation도 있는 경우, 응답을 완전히 처리한 것으로 간주됩니다. 컨트롤러가 긍정적인 ETag 또는 lastModified 타임스탬프 검사를 수행한 경우에도 마찬가지입니다(자세한 내용은 컨트롤러 참조). 위의 어느 것도 참이 아닌 경우 void 반환 유형은 REST 컨트롤러의 경우 "응답 본문 없음"을 나타내거나 HTML 컨트롤러의 경우 기본 뷰 이름 선택을 나타낼 수도 있습니다. |
| Any other return value | 반환 값이 위의 어느 것과도 일치하지 않고 단순 유형(BeanUtils#isSimpleProperty에 의해 결정됨)이 아닌 경우 기본적으로 모델에 추가될 모델 속성으로 처리됩니다. 단순 유형인 경우 해결되지 않은 상태로 유지됩니다. |
REST 서비스에 대한 일반적인 요구 사항은 응답 본문에 오류 세부 정보를 포함하는 것입니다. 응답 본문의 오류 세부 정보 표현은 애플리케이션에 따라 다르기 때문에 Spring Framework는 이를 자동으로 수행하지 않습니다. 그러나 @RestController는 ResponseEntity 반환 값과 함께 @ExceptionHandler 메서드를 사용하여 응답의 상태와 본문을 설정할 수 있습니다. 이러한 메서드는 @ControllerAdvice 클래스에서 선언하여 전역적으로 적용할 수도 있습니다.
응답 본문에 오류 세부 정보를 사용하여 전역 예외 처리를 구현하는 애플리케이션은 Spring MVC에서 발생하는 예외에 대한 처리를 제공하고 응답 본문을 사용자 정의하기 위한 후크를 제공하는 ResponseEntityExceptionHandler 확장을 고려해야 합니다. 이를 활용하기 위해서는 ResponseEntityExceptionHandler의 서브클래스를 생성하고 @ControllerAdvice로 annotation을 달고 필요한 메소드를 오버라이드하고 스프링 빈으로 선언한다.
@ExceptionHandler, @InitBinder 및 @ModelAttribute 메서드는 선언된 @Controller 클래스 또는 클래스 계층에만 적용됩니다. 대신 @ControllerAdvice 또는 @RestControllerAdvice 클래스에서 선언되면 모든 컨트롤러에 적용됩니다. 또한 5.3부터 @ControllerAdvice의 @ExceptionHandler 메서드를 사용하여 @Controller 또는 다른 핸들러의 예외를 처리할 수 있습니다.
@ControllerAdvice는 @Component로 메타 어노테이션이 되어 있으므로 컴포넌트 스캐닝을 통해 Spring Bean으로 등록할 수 있습니다. @RestControllerAdvice는 @ControllerAdvice 및 @ResponseBody로 메타 어노테이션이 달렸습니다. 즉, @ExceptionHandler 메서드는 HTML 뷰가 아니라 응답 본문 메시지 변환을 통해 렌더링된 반환 값을 갖게 됩니다.
시작 시, RequestMappingHandlerMapping 및 ExceptionHandlerExceptionResolver는 controller advice 빈을 감지하고 런타임에 이를 적용합니다. @ControllerAdvice의 전역 @ExceptionHandler 메서드는 @Controller의 로컬 메서드 다음에 적용됩니다. 대조적으로 전역 @ModelAttribute 및 @InitBinder 메서드는 로컬 메서드보다 먼저 적용됩니다.
@ControllerAdvice annotation에는 적용되는 컨트롤러 및 핸들러 세트의 범위를 좁힐 수 있는 속성이 있습니다. 예를 들어:
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
앞의 예에서 selectors는 런타임에 평가되며 광범위하게 사용되는 경우, 성능에 부정적인 영향을 미칠 수 있습니다. 자세한 내용은 @ControllerAdvice javadoc을 참조하십시오.