[번역] Spring 공식문서 - Spring Web MVC
Ref. Spring Framework Documentation v.5.3.16
📌 이 글에서는 공식문서의 Spring Web MVC 부분만 다룹니다.
Spring Web MVC
Spring Web MVC는 Servlet API를 기반으로 구축된 독창적인 웹 프레임워크이며 처음부터 Spring Framework에 포함되었습니다. 정식 명칭인 "Spring Web MVC"는 해당 소스 모듈(spring-webmvc
)의 이름에서 유래하지만 일반적으로 "Spring MVC"로 알려져 있습니다.
Spring Web MVC와 병행하여, Spring Framework 5.0은 "Spring WebFlux"라는 이름의 리액티브 스택 웹 프레임워크를 도입했으며, 그 이름도 해당 소스 모듈(spring-webflux
)을 기반으로 합니다. 이 섹션에서는 Spring 웹 MVC를 다룹니다. 다음 섹션에서는 Spring WebFlux를 다룹니다.
Servlet 컨테이너 및 Java EE 버전 범위와의 기준 정보 및 호환성은 Spring Framework Wiki를 참조하십시오.
DispatcherServlet
다른 많은 웹 프레임워크와 마찬가지로 Spring MVC는 중앙 Servlet
인 DispatcherServlet
이 요청 처리를 위한 공유 알고리즘을 제공하는 반면 실제 작업은 구성 가능한 대리자 구성 요소에 의해 수행되는 전면 컨트롤러 패턴을 중심으로 설계되었습니다. 이 모델은 유연하고 다양한 워크플로우를 지원합니다.
DispatcherServlet
은 모든 Servlet
과 마찬가지로 Java configuration을 사용하거나 web.xml
에서 Servlet 사양에 따라 선언되고 매핑되어야 합니다. 차례로 DispatcherServlet
은 Spring configuration을 사용하여 request mapping, view resolution, exception handling 등에 필요한 대리자 구성 요소를 검색합니다.
- Java configuration
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
web.xml
configuration
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
Context Hierarchy
DispatcherServlet
은 자체 구성을 위해 WebApplicationContext
(일반 ApplicationContext
의 extension)를 필요로 합니다. WebApplicationContext
에는 ServletContext
및 연관된 Servlet
에 대한 링크가 있습니다. 또한 응용 프로그램이 액세스가 필요한 경우 WebApplicationContext
를 조회하기 위해 RequestContextUtils
의 정적 메서드를 사용할 수 있도록 ServletContext
에 바인딩됩니다.
많은 애플리케이션에서 단일 WebApplicationContext
를 갖는 것은 간단하고 충분합니다. 하나의 루트 WebApplicationContext
가 여러 DispatcherServlet
(또는 다른 Servlet
) 인스턴스에서 공유되는 컨텍스트 계층을 가질 수도 있으며, 각각은 자체 자식 WebApplicationContext
구성을 가지고 있습니다. 컨텍스트 계층 기능에 대한 자세한 내용은 ApplicationContext
의 추가 기능을 참조하세요.
루트 WebApplicationContext
는 일반적으로 여러 Servlet
인스턴스에서 공유해야 하는 데이터 저장소 및 비즈니스 서비스와 같은 인프라 빈을 포함합니다. 이러한 빈은 효과적으로 상속되며 일반적으로 지정된 서블릿에 로컬인 빈을 포함하는 Servlet
관련 자식 WebApplicationContext
에서 재정의(즉, 다시 선언)될 수 있습니다. 다음 이미지는 이 관계를 보여줍니다.
다음 예제에서는 WebApplicationContext
계층을 구성합니다.
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
}
다음 예는 web.xml
에 해당하는 것을 보여줍니다.
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app1-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app1</servlet-name>
<url-pattern>/app1/*</url-pattern>
</servlet-mapping>
</web-app>
Annotated Controllers
Spring MVC는 @Controller
및 @RestController
구성 요소가 어노테이션을 사용하여 요청 매핑, 요청 입력, 예외 처리 등을 표현하는 어노테이션 기반 프로그래밍 모델을 제공합니다. 어노테이션이 달린 컨트롤러는 유연한 메서드 서명을 가지고 있으며 기본 클래스를 확장하거나 특정 인터페이스를 구현할 필요가 없습니다. 다음 예는 어노테이션으로 정의된 컨트롤러를 보여줍니다.
@Controller
public class HelloController {
@GetMapping("/hello")
public String handle(Model model) {
model.addAttribute("message", "Hello World!");
return "index";
}
}
앞의 예에서 메서드는 Model
을 인자로 받고 뷰 이름을 String
으로 반환합니다.
Declaration
서블릿의 WebApplicationContext
에서 표준 Spring 빈 정의를 사용하여 컨트롤러 빈을 정의할 수 있습니다. @Controller
스테레오타입은 클래스 경로에서 @Component
클래스를 감지하고 이에 대한 빈 정의를 자동 등록하기 위한 Spring 일반 지원에 맞춰 자동 감지를 허용합니다. 또한 어노테이션이 달린 클래스에 대한 스테레오타입 역할을 하여 웹 구성 요소로서의 역할을 나타냅니다.
이러한 @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>
Request Mapping
@RequestMapping
어노테이션을 사용하여 요청을 컨트롤러 메서드에 매핑할 수 있습니다. URL, HTTP 메서드, 요청 매개변수, 헤더 및 미디어 유형별로 일치하는 다양한 속성이 있습니다. 클래스 수준에서 이를 사용하여 공유 매핑을 표현하거나 메서드 수준에서 특정 끝점 매핑으로 범위를 좁힐 수 있습니다.
@RequestMapping
의 HTTP 메서드 특정 shortcut 변형도 있습니다.
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
shortcuts는 대부분의 컨트롤러 메서드가 기본적으로 모든 HTTP 메서드와 일치하는 @RequestMapping
을 사용하는 대신 특정 HTTP 메서드에 매핑되어야 하기 때문에 제공되는 Custom Annotations입니다. @RequestMapping
은 여전히 클래스 수준에서 공유 매핑을 표현하는 데 필요합니다.
다음 예제에는 타입 및 메서드 수준 매핑이 있습니다.
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
Handler Methods
@RequestMapping
핸들러 메서드는 유연한 서명을 가지고 있으며 지원되는 컨트롤러 메서드 인수 및 반환 값 범위에서 선택할 수 있습니다.
@RequestParam
@RequestParam
어노테이션을 사용하여 서블릿 요청 매개변수(즉, 쿼리 매개변수 또는 양식 데이터)를 컨트롤러의 메소드 인수에 바인딩할 수 있습니다.
다음 예에서는 그렇게 하는 방법을 보여줍니다.
@Controller
@RequestMapping("/pets")
public class EditPetForm {
// ...
@GetMapping
public String setupForm(@RequestParam("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
}
@RequestHeader
@RequestHeader
어노테이션을 사용하여 요청 헤더를 컨트롤러의 메서드 인수에 바인딩할 수 있습니다.
헤더가 있는 다음 요청을 고려하십시오.
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,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
@CookieValue
@CookieValue
어노테이션을 사용하여 HTTP 쿠키 값을 컨트롤러의 메서드 인수에 바인딩할 수 있습니다.
다음 쿠키가 있는 요청을 고려하십시오.
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
다음 예는 쿠키 값을 가져오는 방법을 보여줍니다.
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}
@ModelAttribute
메소드 인수에 @ModelAttribute
어노테이션을 사용하여 모델의 속성에 액세스하거나 존재하지 않는 경우 인스턴스화할 수 있습니다. 모델 속성은 이름이 필드 이름과 일치하는 HTTP Servlet 요청 매개변수의 값으로 겹쳐집니다. 이를 데이터 바인딩이라고 하며 개별 쿼리 매개변수 및 양식 필드의 구문 분석 및 변환을 처리하지 않아도 됩니다. 다음 예에서는 그렇게 하는 방법을 보여줍니다.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
위의 Pet 인스턴스는 다음 방법 중 하나로 소싱됩니다.
@ModelAttribute
메소드에 의해 추가되었을 수 있는 모델에서 검색됩니다.- 모델 속성이 클래스 수준
@SessionAttributes
어노테이션에 나열된 경우 HTTP 세션에서 검색됩니다. - 모델 속성 이름이 경로 변수 또는 요청 매개변수와 같은 요청 값의 이름과 일치하는 변환기를 통해 가져옵니다.
- 기본 생성자를 사용하여 인스턴스화됩니다.
- 서블릿 요청 매개변수와 일치하는 인수를 사용하여 "기본 생성자"를 통해 인스턴스화합니다. 인수 이름은 JavaBeans
@ConstructorProperties
를 통해 또는 바이트 코드에서 런타임에 유지되는 매개변수 이름을 통해 결정됩니다.
@SessionAttributes
@SessionAttributes
는 요청 사이의 HTTP 서블릿 세션에 모델 속성을 저장하는 데 사용됩니다. 특정 컨트롤러에서 사용하는 세션 속성을 선언하는 유형 수준 어노테이션입니다. 여기에는 일반적으로 액세스할 후속 요청을 위해 세션에 투명하게 저장되어야 하는 모델 속성의 이름 또는 모델 속성 유형이 나열됩니다.
다음 예제에서는 @SessionAttributes
어노테이션을 사용합니다.
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
첫 번째 요청에서 이름이 pet
인 모델 속성이 모델에 추가되면 자동으로 HTTP 서블릿 세션으로 승격되어 저장됩니다. 다음 예제와 같이 다른 컨트롤러 메서드가 SessionStatus
메서드 인수를 사용하여 저장소를 지울 때까지 그대로 유지됩니다.
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
@SessionAttribute
전역적으로 관리되는 기존 세션 속성에 액세스해야 하는 경우(즉, 컨트롤러 외부 — 예를 들어 필터에 의해) 존재하거나 존재하지 않을 수 있는 경우, 다음과 같이 메소드 매개변수에 @SessionAttribute
어노테이션을 사용할 수 있습니다. 다음 예는 이것을 보여줍니다.
@RequestMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}
@RequestAttribute
@SessionAttribute
와 유사하게 @RequestAttribute
어노테이션을 사용하여 이전에 생성된 기존 요청 속성(예: Servlet Filter
또는 HandlerInterceptor
에 의해)에 액세스할 수 있습니다.
@GetMapping("/")
public String handle(@RequestAttribute Client client) {
// ...
}
Redirect Attributes
기본적으로 모든 모델 속성은 리디렉션 URL에서 URI 템플릿 변수로 노출되는 것으로 간주됩니다. 나머지 속성 중 기본 유형 또는 기본 유형의 컬렉션 또는 배열인 속성은 자동으로 쿼리 매개변수로 추가됩니다.
모델 인스턴스가 리디렉션을 위해 특별히 준비된 경우 기본 유형 속성을 쿼리 매개변수로 추가하면 원하는 결과가 될 수 있습니다. 그러나 주석이 달린 컨트롤러에서 모델은 렌더링 목적으로 추가된 추가 속성(예: 드롭다운 필드 값)을 포함할 수 있습니다. 이러한 속성이 URL에 나타날 가능성을 피하기 위해 @RequestMapping
메서드는 RedirectAttributes
유형의 인수를 선언하고 이를 사용하여 RedirectView
에서 사용할 수 있도록 정확한 속성을 지정할 수 있습니다. 메서드가 리디렉션하는 경우 RedirectAttributes
의 콘텐츠가 사용됩니다. 그렇지 않으면 모델의 내용이 사용됩니다.
RequestMappingHandlerAdapter
는 ignoreDefaultModelOnRedirect
라는 flag를 제공합니다. 이를 사용하여 컨트롤러 메서드가 리디렉션되는 경우 기본 모델의 콘텐츠를 사용해서는 안 된다는 것을 나타낼 수 있습니다. 대신 컨트롤러 메서드는 RedirectAttributes
유형의 속성을 선언해야 하며 그렇게 하지 않는 경우 속성이 RedirectView
에 전달되어서는 안 됩니다. MVC 네임스페이스와 MVC Java 구성 모두 이전 버전과의 호환성을 유지하기 위해 이 flag를 false
로 설정합니다. 그러나 새 응용 프로그램의 경우 true
로 설정하는 것이 좋습니다.
현재 요청의 URI 템플릿 변수는 리디렉션 URL을 확장할 때 자동으로 사용 가능하게 되며 Model
또는 RedirectAttributes
를 통해 명시적으로 추가할 필요가 없습니다. 다음 예는 리디렉션을 정의하는 방법을 보여줍니다.
@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}
Multipart
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
어노테이션이 어노테이션에 지정된 매개변수 이름 없이 Map<String, MultipartFile>
또는 MultiValueMap<String, MultipartFile>
로 선언되면 맵은 지정된 각 매개변수 이름에 대한 멀티파트 파일로 채워집니다.
명령 개체에 대한 데이터 바인딩의 일부로 멀티파트 콘텐츠를 사용할 수도 있습니다. 예를 들어, 이전 예제의 양식 필드와 파일은 다음 예제와 같이 양식 개체의 필드일 수 있습니다.
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";
}
}
@RequestBody
@RequestBody
어노테이션을 사용하여 요청 본문을 읽고 HttpMessageConverter
를 통해 Object
로 역직렬화하도록 할 수 있습니다. 다음 예제에서는 @RequestBody
인수를 사용합니다.
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
HttpEntity
HttpEntity
는 @RequestBody
를 사용하는 것과 거의 동일하지만 요청 헤더와 본문을 노출하는 컨테이너 개체를 기반으로 합니다. 다음 목록은 예를 보여줍니다.
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
@ResponseBody
메서드에 @ResponseBody
어노테이션을 사용하여 HttpMessageConverter
를 통해 응답 본문에 반환을 직렬화할 수 있습니다. 다음 목록은 예를 보여줍니다.
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
ResponseEntity
ResponseEntity
는 @ResponseBody
와 비슷하지만 상태와 헤더가 있습니다.
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).build(body);
}
Jackson JSON
Spring은 Jackson JSON 라이브러리에 대한 지원을 제공합니다.
JSON Views
Spring MVC는 객체의 모든 필드의 하위 집합만 렌더링할 수 있는 Jackson의 직렬화 보기에 대한 내장 지원을 제공합니다. @ResponseBody
또는 ResponseEntity
컨트롤러 메서드와 함께 사용하려면 다음 예제와 같이 Jackson의 @JsonView
주석을 사용하여 직렬화 보기 클래스를 활성화할 수 있습니다.
@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;
}
}
Author And Source
이 문제에 관하여([번역] Spring 공식문서 - Spring Web MVC), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@orijoon98/Spring-Framework-Documentation4-Spring-Web-MVC저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)