Handler methods with the @RequestMapping annotation have a flexible signature and can choose from a range of supported controller method arguments and return values.
Method arguments
The following table describes supported controller method arguments. Reactive types are not supported for any arguments.
The java.util.Optional argument from JDK 8 is supported as a method argument in combination with annotations that have the required attribute (for example, @RequestParam, @RequestHeader and others), and is equivalent to required=false.
| Controller method argument | Description |
|---|---|
|
Provides typed access to request parameters and request and session attributes, without directly using the Servlet API. |
|
Intended to select any specific type of request or response - for example, |
|
Ensures that a session exists. As a consequence, such an argument is never |
|
Servlet 4.0 build pusher API for programmatic push ) HTTP/2 resources. Note that, according to the Servlet specification, the injected |
|
The current authenticated user - possibly a concrete implementation class of Note that this argument is not accelerated recognized if it has an annotation designed to allow a custom resolver to recognize it before falling back to default recognition via |
|
HTTP request method. |
|
The current locale of the request, determined by the most specific |
|
The time zone associated with the current request, as determined by the |
|
Designed to provide access to the raw request body as it is presented in the Servlet API. |
|
Designed to provide access to the raw response body exposed by the Servlet API. |
|
Designed to provide access to URI pattern variables. |
|
Designed to provide access to pairs "name-value" in URI path segments. |
|
Designed to provide access to servlet request parameters, including multipart files. Parameter values are converted to the declared type of the method arguments. Note that the use of the |
|
Designed to provide access to request headers. Header values are converted to the declared type of the method argument. |
|
Designed to provide access to cookies . Cookie values are converted to the declared method argument type. |
|
To access the HTTP request body. The body content is converted to the declared method argument type using |
|
Designed to provide access to request headers and body. The body is converted using |
|
Designed to provide access to a component in a |
|
Designed to provide access to a model that is used in HTML controllers and exposed in templates as part of the view rendering. |
|
Specifies the attributes that will be used in the event of a redirect (that is, will be added to request line), flash attributes that will be temporarily stored until the request arrives after a redirect. |
|
To access an existing attribute in the model (of which an instance is created if it is missing) with data binding and validation. Note that use the |
|
Designed to provide access to validation and data binding errors for a command object (that is, an argument with the |
|
Intended to mark completion of form processing, which causes session attributes declared through the |
|
Designed to prepare a URL associated with the host, port, scheme, context path of the current request, and servlet mapping literal component. |
|
Designed to provide access to any session attribute, as opposed to model attributes, stored in the session as a result of declaring the |
|
Designed to provide access to request attributes. |
Any other argument |
If argument method does not match any of the previous values in this table and is a simple type (as defined by BeanUtils#isSimpleProperty), it resolves to |
Return values
In the following The table describes the supported return values of the controller method. Reactive types are supported for all return values.
| Return value of the controller method | Description |
|---|---|
|
The return value is converted through the |
|
Return value specifying the full response (including HTTP headers and body), converted through the |
|
Designed to return a response with headers and no body. |
|
The name of the view to be recognized by |
|
A |
|
Attributes added to the implicit model, with the view name implicitly defined via |
|
Attribute , added to the model whose view name is implicitly specified via Note that the |
|
The view and model attributes to use and, if necessary, the response status. |
|
A method with a return type If neither of the above is true, the return type is |
|
Produces any of the previous return values asynchronously from any thread - for example, as a result of an event or callback. |
|
Produces any of the above returned values asynchronously in a thread managed by Spring MVC. |
|
A more convenient alternative to |
|
Asynchronously spawns a stream of objects to write to the response using |
|
Asynchronous writing to |
Reactive types - Reactor, RxJava, or others via |
Alternative to In streaming scenarios (for example, |
Any other return value |
Any return value that does not match any of previous values in this table and is a |
Type conversion
Some annotated controller method arguments representing request input based on String (such as @RequestParam, @RequestHeader, @PathVariable, @MatrixVariable and @CookieValue) may require a type conversion if the argument is not declared as a String.
In such cases, the type conversion is applied automatically based on the configured converters. By default, simple types are supported (int, long, Date and others). You can configure type conversion via WebDataBinder or by registering Formatters with the FormattingConversionService.
A practical issue with type conversion is handling empty the original value of the string. Such a value is considered missing if it becomes null as a result of a type conversion. This may be true for Long, UUID and other target types. If you need to allow null injection, then either use the required flag in the argument annotation, or declare the argument as @Nullable.
Starting in version 5.3, non-null arguments will be honored even after type conversion. If the handler method is expected to accept a null value, then either declare the argument as @Nullable, or mark it as required=false in the appropriate @RequestParam etc. This is the best practice and recommended solution for regressions encountered when upgrading to version 5.3.
In addition, you can specially handle, for example, the MissingPathVariableException exception that is raised if the annotation @PathVariable is required. A Null value after conversion will be treated as an empty original value, so the corresponding Missing...Exception exception will be generated.
Matrix Variables
In RFC 3986 describes name-value pairs in path segments. In Spring MVC we call them "matrix variables", based on "old post" by Tim Berners-Lee, but can also be called URI path parameters.
Matrix variables can appear in any path segment, with each variable separated by a semicolon and multiple values separated by a comma (for example, /cars;color=red,green;year=2012). Multiple values can also be specified through repeated variable names (for example, color=red;color=green;color=blue).
If the URL is expected to contain matrix variables, then the request mapping for a controller method must use a URI variable to mask the contents of such a matrix variable and ensure successful request mapping regardless of the order or presence of the matrix variables. The following example uses a matrix variable:
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) {
// petId == 42
// q == 11
}
Given that all path segments can contain matrix variables, sometimes it can you will need to determine which path variable the matrix variable should be in. The following example shows how to do this:
// 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 /owners/42;q=11/pets/21;q=22
@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
}
A matrix variable can be defined as optional and have a default value, as shown in the following example:
// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
// q == 1
}
// GET /pets/42
@GetMapping("/pets/{petId}")
fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) {
// q == 1
}
To get all matrix variables, you can use MultiValueMap as shown in the following example:
// 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]
}
// 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]
}
Please note that the use of matrix variables must be enabled. In MVC configuration in Java, you need to set UrlPathHelper when removeSemicolonContent=false via Path Matching. In the MVC namespace on XML you can set <mvc:annotation-driven enable-matrix-variables="true"/>.
@RequestParam
The @RequestParam annotation can be used to bind servlet request parameters (that is, request parameters or form data) to a method argument in the controller.
In the following example shows how to do this:
@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";
}
// ...
}
- Using the
@RequestParamannotation for bindingspetId.
import org.springframework.ui.set
@Controller
@RequestMapping("/pets" )
class EditPetForm {
// ...
@GetMapping
fun setupForm(@RequestParam("petId") petId: Int, model: Model): String {
val pet = this.clinic.loadPet(petId);
model["pet"] = pet
return "petForm"
}
// ...
}
- Using the
@RequestParamannotation to bind thepetId.
By default, method parameters that use this annotation are required, but you can specify that the method parameter is optional by setting the required flag of the @RequestParam annotation to false or by declaring the argument using the java.util.Optional wrapper function.
Type conversion is applied automatically if the target method's parameter type is not String.
Declaring the argument type as an array or list allows multiple parameter values for the same parameter name.
If the @RequestParam annotation is declared as Map<String, String> or MultiValueMap<String , String> without specifying a parameter name in the annotation, then the Map is populated with the request parameter values for each given parameter name.
Note that using the @RequestParam annotation is optional (for example, to set attributes). By default, any argument that is a simple value type (as defined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver, is treated as if it were annotated with @RequestParam.
@RequestHeader
You can use the @RequestHeader annotation to bind the request header to a method argument in the controller.
Consider the following request with headers:
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
The following example shows how to get the value of the Accept-Encoding headers and Keep-Alive:
@GetMapping("/demo")
public void handle(
@RequestHeader(" Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
- We get the values of the
Accept-Encodingheader. - We get the values of the
Keep-Aliveheader.
@GetMapping("/demo")
fun handle(
@RequestHeader("Accept-Encoding") encoding: String,
@RequestHeader("Keep-Alive") keepAlive: Long) {
//...
}
- Get the values of the
Accept-Encodingheader. - Get the values of the header
Keep-Alive.
If the target method parameter type is not String, type conversion is applied automatically.
If the @RequestHeader annotation is used in a Map<String, String>, MultiValueMap<String, String>, or HttpHeaders argument , The Map is populated with all header values.
@RequestHeader("Accept") can be of type
String, as well as
String[] or
List<String>.
@CookieValue
The @CookieValue annotation can be used to bind HTTP data type values cookie to a method argument in the controller.
Consider a request with the following cookie:
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
The following example shows how to get the cookie value:
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//. ..
}
- Getting the
JSESSIONIDcookie value.
@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) {
//...
}
- Get the value of the
JSESSIONIDcookie.
If the target method parameter type is not String, type conversion is applied automatically.
@ModelAttribute
The @ModelAttribute annotation can be used on a method argument to access the attribute from the model or create an instance of it if it is missing. The model attribute is also overlaid with values from the servlet request parameters via HTTP, the names of which coincide with the names of the fields. This is called data binding, and it eliminates the need to parse and transform individual query parameters and form fields. The following example shows how to do this:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
@PostMapping( "/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String {
// method logic...
}
The above Pet instance is obtained in one of the following ways:
Retrieved from the model where it may have been added by a method with the @ModelAttribute annotation.
Retrieved from the HTTP session if the model attribute was specified in the
@SessionAttributesannotation at the class level.Received through some kind of
Converter, where the name of the model attribute is the same as the name of the request value, for example, a path variable or request parameter (see. following example).Created using the default constructor.
Created via the "primary constructor" with arguments corresponding to the parameters servlet request. Argument names are specified through the
@ConstructorPropertiesannotation of JavaBeans classes or through run-time bytecode-stored parameter names.
An alternative to using a method with the @ModelAttribute annotation to provide it, or to call the framework to create a model attribute, is to use Converter<String, T> to provide an instance. This is applicable if the model attribute name is the same as the name of a query value, such as a path variable or query parameter, and there is a Converter from String to the model attribute type. In the following example, the model attribute name is account, which corresponds to the URI path variable account, and there is also a registered Converter<String, Account>. which can load Account from the data store:
@PutMapping("/accounts/{account}")
public String save( @ModelAttribute("account") Account account) {
// ...
}
@PutMapping ("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String {
// ...
}
After receiving the model attribute instance, data binding is applied. The WebDataBinder class maps servlet request parameter names (query parameters and form fields) to target object field names. Matched fields are populated after applying type conversion where necessary.
Data binding can cause errors. By default, a BindException exception is thrown. However, to check for such errors in a controller method, you can add a BindingResult argument directly next to the @ModelAttribute annotation, as shown in the following example:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Adding
BindingResultnext to the annotation@ModelAttribute.
@PostMapping("/owners/{ownerId}/pets/{petId}/ edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors ()) {
return "petForm"
}
// ...
}
- Adding
BindingResultnext to the@ModelAttributeannotation.
In some cases, you may need to access a model attribute without data binding. For such cases, you can inject a Model into the controller and access it directly, or alternatively set @ModelAttribute(binding=false), as shown in the following example:
@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) {
// ...
}
- Setting
@ModelAttribute(binding=false).
@ModelAttribute
fun setUpForm(): AccountForm {
return AccountForm()
}
@ModelAttribute
fun findAccount(@PathVariable accountId : String): Account {
return accountRepository.findOne(accountId)
}
@PostMapping("update")
fun update(@Valid form: AccountForm, result: BindingResult,
@ModelAttribute(binding = false) account: Account): String {
// ...
}
- Setting
@ModelAttribute(binding=false).
You can automatically apply validation after data binding by adding the javax.validation.Valid annotation or the @Validated annotation from Spring. The following example shows how to do this:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
- Validate the
Petinstance.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute( "pet") pet: Pet, result: BindingResult): String {
if (result.hasErrors()) {
return "petForm"
}
// ...
}
Note that using the @ModelAttribute annotation is optional (for example, to set attributes). By default, any argument that is not a simple value type (as defined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver, is treated as if it were annotated with @ModelAttribute.
@SessionAttributes
The @SessionAttributes annotation is used to store model attributes in a servlet HTTP session between requests. This is a type-level annotation that declares the session attributes used by a particular controller. This typically lists the model attribute names or model attribute types that should be transparently stored in the session for subsequent access requests.
The following example uses the @SessionAttributes annotation:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
- Using the
@SessionAttributesannotation.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
}
- Using the
@SessionAttributesannotation.
On the first request, when a model attribute named pet is added to the model, it is automatically promoted and stored in the servlet's HTTP session. It remains there until another controller method uses the SessionStatus method argument to clear the storage, as shown in the following example:
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
@PostMapping("/pets/{id }")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
- Storing the
Petvalue in the servlet session. - Clearing the
Petvalue from the servlet session.
@Controller
@SessionAttributes("pet")
class EditPetForm {
// ...
@PostMapping("/pets/{id}")
fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String {
if (errors.hasErrors()) {
// ...
}
status.setComplete()
// ...
}
}
- Storing the
Petvalue in the servlet session. - Clearing the
Petvalue from the servlet session.
@SessionAttribute
If you need access to pre-existing session attributes that are managed globally (that is, outside the controller - for example, by a filter) and can present or absent, you can use the @SessionAttribute annotation on the method parameter, as shown in the following example:
@RequestMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}
- Using the
@SessionAttributeannotation.
@RequestMapping("/")
fun handle(@SessionAttribute user: User): String {
// ..
}
For use cases that require adding or removing session attributes, consider implementing org.springframework.web.context.request.WebRequest or javax.servlet.http.HttpSession into a controller method.
To temporarily store model attributes in a session as part of the controller workflow, consider using the @SessionAttributes annotation.
@RequestAttribute
Similar to the @SessionAttribute annotation, you can use the @RequestAttribute to provide access to existing request attributes created earlier (for example, Filter or HandlerInterceptor servlets):
@GetMapping("/")
public String handle(@RequestAttribute Client client) {
// ...
}
- Using the
@RequestAttributeannotation.
@GetMapping("/")
fun handle(@RequestAttribute client: Client): String {
// ...
}
- Using the
@ annotation RequestAttribute.
Redirect Attributes
By default, all model attributes are considered to be in the form of a URI pattern in the redirect URL. Of the remaining attributes, those that are primitive types or collections or arrays of primitive types are automatically added as query parameters.
Adding primitive type attributes as query parameters may be the desired result if the model instance was prepared specifically for redirection However, in annotated controllers, the model may contain additional attributes added for visualization purposes (for example, dropdown field values). To avoid such attributes appearing in the URL, a method marked with the @RequestMapping annotation can declare an argument of type RedirectAttributes and use it to specify the exact attributes that should be available RedirectView. If the method performs a redirect, the contents of RedirectAttributes are used. Otherwise, the contents of the model are used.
RequestMappingHandlerAdapter provides a ignoreDefaultModelOnRedirect flag that can be used to indicate that the contents of the default Model should never be used in a redirect controller method. Instead, the controller method must declare an attribute of type RedirectAttributes, or, if it does not, then no attributes should be passed to RedirectView. In both the MVC namespace and the Java MVC configuration, this flag is set to false to maintain backward compatibility. However, for new applications, we recommend setting this to true.
Note that the URI template variables from this request are automatically made available when the redirect URL is expanded, so add them explicitly via Model or RedirectAttributes is not required. The following example shows how to define a redirect:
@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}
@PostMapping("/files/{path}")
fun upload(... ): String {
// ...
return "redirect:files/{path}"
}
Another way to pass data to the redirect target is to use flash attributes . Unlike other redirect attributes, flash attributes are temporarily stored in the HTTP session (and therefore are not displayed in the URL).
Flash attributes
Flash attributes provide the ability to store attributes one request, intended for use in another request. Most often this is needed when redirecting - for example, the Post-Redirect-Get pattern. Flash attributes are temporarily stored before a redirect (usually in a session) so that they are available for request after the redirect, and are then immediately removed.
Spring MVC has two main abstractions for supporting flash attributes. FlashMap is used to store flash attributes, and FlashMapManager is used to store, retrieve, and manage instances of FlashMap.
Support for flash attributes is always "on" and does not require explicit activation. However, if it is not used, it will never create an HTTP session. With each request, there is an "input" FlashMap with the attributes passed in from the previous request (if any), and an "output" FlashMap with the attributes that need to be saved for the subsequent request. Both FlashMap instances are accessible from anywhere in Spring MVC via static methods in RequestContextUtils.
Annotated controllers generally do not need to work directly with FlashMap. Instead, a method annotated with @RequestMapping can take an argument of type RedirectAttributes and use it to add flash attributes for the redirection script. Flash attributes added via RedirectAttributes are automatically propagated to the "output" FlashMap. Likewise, after a redirect, attributes from the "input" FlashMap are automatically added to the Model of the controller serving the target URL.
Multipart
After activating the MultipartResolver the contents of POST requests with multipart/form-data is parsed and becomes available as normal request parameters. The following example accesses one regular form field and one uploaded file:
@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";
}
}
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(@RequestParam("name") name: String,
@RequestParam("file") file: MultipartFile): String {
if (!file.isEmpty) {
val bytes = file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Declaring the argument type as List<MultipartFile> allows you to allow multiple files for one and same parameter name.
If the @RequestParam annotation is declared as Map<String, MultipartFile> or MultiValueMap<String, MultipartFile> without a parameter name specified in the annotation, then the Map is filled with multi-part files for each given parameter name.
javax.servlet.http.Part instead of
MultipartFile from Spring as a method argument or collection value type.
You can also use multipart content as a data binding element to the command object. For example, the form field and file from the previous example could be form object fields, as shown in the following example:
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";
}
}
class MyForm(val name: String, val file: MultipartFile, ...)
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(form: MyForm, errors: BindingResult): String {
if (!form.file.isEmpty) {
val bytes = form.file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
Multi-part requests can also be sent from non-browser clients in a RESTful service scenario. The following example shows a JSON file:
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 ...
You can access the " metadata" with the @RequestParam annotation as a String, but you'll probably want it to be deserialized from JSON (similar to the @RequestBody annotation code>). Use the @RequestPart annotation to access a multi-part file after it has been converted using HttpMessageConverter:
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData,
@RequestPart("file-data") file: MultipartFile): String {
// ...
}
You can use the @RequestPart annotation in combination with javax.validation.Valid or use the @Validated annotation from Spring, which causes the standard Bean Validation to be applied. By default, validation errors result in a MethodArgumentNotValidException exception, which turns into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally in the controller via the Errors or BindingResult argument, as shown in the following example:
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
result: BindingResult): String {
// ...
}
@RequestBody
Annotation @RequestBody can be used so that the body of the request can be read and deserialized into a Object via the HttpMessageConverter. The following example uses an argument with the @RequestBody annotation:
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
The Message Converters option in the MVC configuration can be used to configure or configure message conversion.
You can use the @RequestBody annotation in combination with javax.validation.Valid or the @Validated annotation from Spring, which trigger the application standard Bean Validation. By default, validation errors result in a MethodArgumentNotValidException exception, which turns into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally in the controller via the Errors or BindingResult argument, as shown in the following example:
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Account, result: BindingResult) {
// ...
}
HttpEntity
The HttpEntity class is more or less identical in terms of using the @RequestBody annotation, but is based on a container object that exposes the request headers and body. The following listing is an example:
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
@PostMapping("/accounts")
fun handle(entity: HttpEntity<Account>) {
// ...
}
@ResponseBody
Annotation @ResponseBodycan be used for a method to have the return serialized into the response body via HttpMessageConverter. The following listing is an example:
@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}
@GetMapping("/accounts/{id}")
@ResponseBody
fun handle(): Account {
// ...
}
@ResponseBody is also supported at the class level, in which case it is inherited by all methods controller. This is the effect of the @RestController annotation, which is nothing more than a meta annotation marked with the @Controller and @ResponseBody annotations.
You can use @ResponseBody with reactive types.
You can use the Message Converters option in the MVC configuration to configure or customize message conversion.
You can combine methods marked with the @ResponseBody annotation, with serialization representations in JSON format.
ResponseEntity
The ResponseEntity class is similar to the @ResponseBody annotation, but with status and headings. For example:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).body(body);
}
@GetMapping("/something")
fun handle(): ResponseEntity<String> {
val body = ...
val etag = ...
return ResponseEntity.ok().eTag(etag).build(body)
}
Spring MVC supports the use of a single-value reactive type to asynchronously create a ResponseEntity, and/or single- and multi-value reactive types for the body. This allows the following types of asynchronous responses:
ResponseEntity<Mono<T>>orResponseEntity<Flux<T>>report the response status and headers immediately, while the response body is provided asynchronously at a later point. UseMonoif the body consists of 0..1 values, orFluxif it can create multiple values.Mono<ResponseEntity<T>>provides all three parameters - response status, headers and body - asynchronously at a later point. This allows you to change the response status and headers depending on the results of asynchronous request processing.
Jackson JSON
Spring provides support for the Jackson JSON library.
JSON Views
Spring MVC provides native support for view serialization Jackson's Serialization Views, which allows you to display only a subset of all fields of an object. To use it with controller methods annotated with @ResponseBody, or with the ResponseEntity class, you can leverage the @JsonView annotation from Jackson to activate the serialization view class, like shown in the following example:
@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;
}
}
@RestController
class UserController {
@GetMapping("/user")
@JsonView(User.WithoutPasswordView::class)
fun getUser() = User("eric", "7!jd#h23")
}
class User(
@JsonView(WithoutPasswordView::class) val username: String,
@JsonView(WithPasswordView::class) val password: String) {
interface WithoutPasswordView
interface WithPasswordView : WithoutPasswordView
}
@JsonView allows you to use an array of view classes, but you can only specify one per controller method. If you need to activate multiple views, you can use a composite interface.
If you want to do the above programmatically, instead of declaring the @JsonView annotation wrap the return value with MappingJacksonValue and use it to provide a serialization view:
@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;
}
}
@RestController
class UserController {
@GetMapping("/user")
fun getUser(): MappingJacksonValue {
val value = MappingJacksonValue(User("eric", "7!jd#h23"))
value.serializationView = User.WithoutPasswordView::class.java
return value
}
}
For controllers that use view recognition, you can add a serialization view class to the model, as shown in the following example:
@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";
}
}
import org.springframework.ui.set
@Controller
class UserController : AbstractController() {
@GetMapping("/user")
fun getUser(model: Model): String {
model["user"] = User("eric", "7!jd#h23")
model[JsonView::class.qualifiedName] = User.WithoutPasswordView::class.java
return "userView"
}
}
GO TO FULL VERSION