Migrate to Asciidoctor Tabs

This commit is contained in:
Rob Winch
2023-04-20 16:21:36 -05:00
committed by rstoyanchev
parent 71154fd16b
commit 39146f9066
243 changed files with 7124 additions and 1779 deletions

View File

@@ -23,8 +23,11 @@ By contrast, global `@ModelAttribute` and `@InitBinder` methods are applied _bef
The `@ControllerAdvice` annotation has attributes that let you narrow the set of controllers
and handlers that they apply to. For example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
@@ -38,8 +41,10 @@ and handlers that they apply to. For example:
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = [RestController::class])
@@ -53,6 +58,7 @@ and handlers that they apply to. For example:
@ControllerAdvice(assignableTypes = [ControllerInterface::class, AbstractController::class])
class ExampleAdvice3
----
======
The selectors in the preceding example are evaluated at runtime and may negatively impact
performance if used extensively. See the

View File

@@ -6,8 +6,11 @@
`@Controller` and xref:web/webmvc/mvc-controller/ann-advice.adoc[@ControllerAdvice] classes can have
`@ExceptionHandler` methods to handle exceptions from controller methods, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
public class SimpleController {
@@ -20,8 +23,10 @@
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
class SimpleController {
@@ -34,6 +39,7 @@
}
}
----
======
The exception may match against a top-level exception being propagated (e.g. a direct
`IOException` being thrown) or against a nested cause within a wrapper exception (e.g.
@@ -48,42 +54,54 @@ is used to sort exceptions based on their depth from the thrown exception type.
Alternatively, the annotation declaration may narrow the exception types to match,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: IOException): ResponseEntity<String> {
// ...
}
----
======
You can even use a list of specific exception types with a very generic argument signature,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: Exception): ResponseEntity<String> {
// ...
}
----
======
[NOTE]
====

View File

@@ -21,8 +21,11 @@ do, except for `@ModelAttribute` (command object) arguments. Typically, they are
with a `WebDataBinder` argument (for registrations) and a `void` return value.
The following listing shows an example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
public class FormController {
@@ -37,6 +40,7 @@ The following listing shows an example:
// ...
}
----
======
<1> Defining an `@InitBinder` method.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -61,8 +65,11 @@ Alternatively, when you use a `Formatter`-based setup through a shared
`FormattingConversionService`, you can re-use the same approach and register
controller-specific `Formatter` implementations, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
public class FormController {
@@ -75,6 +82,7 @@ controller-specific `Formatter` implementations, as the following example shows:
// ...
}
----
======
<1> Defining an `@InitBinder` method on a custom formatter.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -15,14 +15,18 @@ JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
The following example shows how to get the cookie value:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { <1>
//...
}
----
======
<1> Get the value of the `JSESSIONID` cookie.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -6,22 +6,28 @@
`HttpEntity` is more or less identical to using xref:web/webmvc/mvc-controller/ann-methods/requestbody.adoc[`@RequestBody`] but is based on a
container object that exposes request headers and body. The following listing shows an example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/accounts")
fun handle(entity: HttpEntity<Account>) {
// ...
}
----
======

View File

@@ -13,8 +13,11 @@ which allow rendering only a subset of all fields in an `Object`. To use it with
`@ResponseBody` or `ResponseEntity` controller methods, you can use Jackson's
`@JsonView` annotation to activate a serialization view class, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RestController
public class UserController {
@@ -53,8 +56,10 @@ which allow rendering only a subset of all fields in an `Object`. To use it with
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RestController
class UserController {
@@ -72,6 +77,7 @@ which allow rendering only a subset of all fields in an `Object`. To use it with
interface WithPasswordView : WithoutPasswordView
}
----
======
NOTE: `@JsonView` allows an array of view classes, but you can specify only one per
controller method. If you need to activate multiple views, you can use a composite interface.
@@ -79,8 +85,11 @@ controller method. If you need to activate multiple views, you can use a composi
If you want to do the above programmatically, instead of declaring an `@JsonView` annotation,
wrap the return value with `MappingJacksonValue` and use it to supply the serialization view:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RestController
public class UserController {
@@ -94,8 +103,10 @@ wrap the return value with `MappingJacksonValue` and use it to supply the serial
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RestController
class UserController {
@@ -108,12 +119,16 @@ wrap the return value with `MappingJacksonValue` and use it to supply the serial
}
}
----
======
For controllers that rely on view resolution, you can add the serialization view class
to the model, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
public class UserController extends AbstractController {
@@ -126,8 +141,10 @@ to the model, as the following example shows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
class UserController : AbstractController() {
@@ -140,6 +157,7 @@ to the model, as the following example shows:
}
}
----
======

View File

@@ -18,8 +18,11 @@ method must use a URI variable to mask that variable content and ensure the requ
be matched successfully independent of matrix variable order and presence.
The following example uses a matrix variable:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// GET /pets/42;q=11;r=22
@@ -30,8 +33,10 @@ The following example uses a matrix variable:
// q == 11
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// GET /pets/42;q=11;r=22
@@ -42,13 +47,17 @@ The following example uses a matrix variable:
// q == 11
}
----
======
Given that all path segments may contain matrix variables, you may sometimes need to
disambiguate which path variable the matrix variable is expected to be in.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// GET /owners/42;q=11/pets/21;q=22
@@ -61,8 +70,10 @@ The following example shows how to do so:
// q2 == 22
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// GET /owners/42;q=11/pets/21;q=22
@@ -75,12 +86,16 @@ The following example shows how to do so:
// q2 == 22
}
----
======
A matrix variable may be defined as optional and a default value specified, as the
following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// GET /pets/42
@@ -90,8 +105,10 @@ following example shows:
// q == 1
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// GET /pets/42
@@ -101,11 +118,15 @@ following example shows:
// q == 1
}
----
======
To get all matrix variables, you can use a `MultiValueMap`, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@@ -118,8 +139,10 @@ To get all matrix variables, you can use a `MultiValueMap`, as the following exa
// petMatrixVars: ["q" : 22, "s" : 23]
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@@ -132,6 +155,7 @@ To get all matrix variables, you can use a `MultiValueMap`, as the following exa
// petMatrixVars: ["q" : 22, "s" : 23]
}
----
======
Note that you need to enable the use of matrix variables. In the MVC Java configuration,
you need to set a `UrlPathHelper` with `removeSemicolonContent=false` through

View File

@@ -9,14 +9,18 @@ values from HTTP Servlet request parameters whose names match to field names. Th
to as data binding, and it saves you from having to deal with parsing and converting individual
query parameters and form fields. The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { // <1>
// method logic...
}
----
======
<1> Bind an instance of `Pet`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -51,14 +55,18 @@ In the following example, the model attribute name is `account` which matches th
path variable `account`, and there is a registered `Converter<String, Account>` which
could load the `Account` from a data store:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) { // <1>
// ...
}
----
======
<1> Bind an instance of `Account` using an explicit attribute name.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -82,8 +90,11 @@ Data binding can result in errors. By default, a `BindException` is raised. Howe
for such errors in the controller method, you can add a `BindingResult` argument immediately next
to the `@ModelAttribute`, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { // <1>
@@ -93,6 +104,7 @@ to the `@ModelAttribute`, as the following example shows:
// ...
}
----
======
<1> Adding a `BindingResult` next to the `@ModelAttribute`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -112,8 +124,11 @@ In some cases, you may want access to a model attribute without data binding. Fo
cases, you can inject the `Model` into the controller and access it directly or,
alternatively, set `@ModelAttribute(binding=false)`, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ModelAttribute
public AccountForm setUpForm() {
@@ -131,6 +146,7 @@ alternatively, set `@ModelAttribute(binding=false)`, as the following example sh
// ...
}
----
======
<1> Setting `@ModelAttribute(binding=false)`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -159,8 +175,11 @@ You can automatically apply validation after data binding by adding the
(xref:core/validation/beanvalidation.adoc[Bean Validation] and
xref:web/webmvc/mvc-config/validation.adoc[Spring validation]). The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { // <1>
@@ -170,6 +189,7 @@ xref:web/webmvc/mvc-config/validation.adoc[Spring validation]). The following ex
// ...
}
----
======
<1> Validate the `Pet` instance.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -8,8 +8,11 @@ requests with `multipart/form-data` is parsed and accessible as regular request
parameters. The following example accesses one regular form field and one uploaded
file:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
public class FileUploadController {
@@ -27,8 +30,10 @@ file:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
class FileUploadController {
@@ -46,6 +51,7 @@ file:
}
}
----
======
Declaring the argument type as a `List<MultipartFile>` allows for resolving multiple
files for the same parameter name.
@@ -62,8 +68,11 @@ xref:web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc[command
and file from the preceding example could be fields on a form object,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
class MyForm {
@@ -88,8 +97,10 @@ as the following example shows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class MyForm(val name: String, val file: MultipartFile, ...)
@@ -107,6 +118,7 @@ as the following example shows:
}
}
----
======
Multipart requests can also be submitted from non-browser clients in a RESTful service
@@ -137,8 +149,11 @@ probably want it deserialized from JSON (similar to `@RequestBody`). Use the
`@RequestPart` annotation to access a multipart after converting it with an
xref:integration/rest-clients.adoc#rest-message-conversion[HttpMessageConverter]:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@@ -146,8 +161,10 @@ xref:integration/rest-clients.adoc#rest-message-conversion[HttpMessageConverter]
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData,
@@ -155,6 +172,7 @@ xref:integration/rest-clients.adoc#rest-message-conversion[HttpMessageConverter]
// ...
}
----
======
You can use `@RequestPart` in combination with `jakarta.validation.Valid` or use Spring's
`@Validated` annotation, both of which cause Standard Bean Validation to be applied.
@@ -163,8 +181,11 @@ into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation erro
within the controller through an `Errors` or `BindingResult` argument,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
@@ -172,8 +193,10 @@ as the following example shows:
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
@@ -181,6 +204,7 @@ as the following example shows:
// ...
}
----
======

View File

@@ -26,8 +26,11 @@ Note that URI template variables from the present request are automatically made
available when expanding a redirect URL, and you don't need to explicitly add them
through `Model` or `RedirectAttributes`. The following example shows how to define a redirect:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/files/{path}")
public String upload(...) {
@@ -35,8 +38,10 @@ through `Model` or `RedirectAttributes`. The following example shows how to defi
return "redirect:files/{path}";
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/files/{path}")
fun upload(...): String {
@@ -44,6 +49,7 @@ through `Model` or `RedirectAttributes`. The following example shows how to defi
return "redirect:files/{path}"
}
----
======
Another way of passing data to the redirect target is by using flash attributes. Unlike
other redirect attributes, flash attributes are saved in the HTTP session (and, hence, do

View File

@@ -7,14 +7,18 @@ Similar to `@SessionAttribute`, you can use the `@RequestAttribute` annotations
access pre-existing request attributes created earlier (for example, by a Servlet `Filter`
or `HandlerInterceptor`):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/")
public String handle(@RequestAttribute Client client) { // <1>
// ...
}
----
======
<1> Using the `@RequestAttribute` annotation.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -7,22 +7,28 @@ You can use the `@RequestBody` annotation to have the request body read and dese
`Object` through an xref:integration/rest-clients.adoc#rest-message-conversion[`HttpMessageConverter`].
The following example uses a `@RequestBody` argument:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
// ...
}
----
======
You can use the xref:web/webmvc/mvc-config/message-converters.adoc[Message Converters] option of the xref:web/webmvc/mvc-config.adoc[MVC Config] to
@@ -35,21 +41,27 @@ into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation erro
within the controller through an `Errors` or `BindingResult` argument,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Account, result: BindingResult) {
// ...
}
----
======

View File

@@ -21,8 +21,11 @@ Keep-Alive 300
The following example gets the value of the `Accept-Encoding` and `Keep-Alive` headers:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/demo")
public void handle(
@@ -31,6 +34,7 @@ The following example gets the value of the `Accept-Encoding` and `Keep-Alive` h
//...
}
----
======
<1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header.

View File

@@ -8,8 +8,11 @@ query parameters or form data) to a method argument in a controller.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
@RequestMapping("/pets")
@@ -28,6 +31,7 @@ The following example shows how to do so:
}
----
======
<1> Using `@RequestParam` to bind `petId`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -8,8 +8,11 @@ to the response body through an
xref:integration/rest-clients.adoc#rest-message-conversion[HttpMessageConverter].
The following listing shows an example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/accounts/{id}")
@ResponseBody
@@ -17,8 +20,10 @@ The following listing shows an example:
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/accounts/{id}")
@ResponseBody
@@ -26,6 +31,7 @@ The following listing shows an example:
// ...
}
----
======
`@ResponseBody` is also supported at the class level, in which case it is inherited by
all controller methods. This is the effect of `@RestController`, which is nothing more

View File

@@ -5,8 +5,11 @@
`ResponseEntity` is like xref:web/webmvc/mvc-controller/ann-methods/responsebody.adoc[`@ResponseBody`] but with status and headers. For example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/something")
public ResponseEntity<String> handle() {
@@ -15,8 +18,10 @@
return ResponseEntity.ok().eTag(etag).body(body);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/something")
fun handle(): ResponseEntity<String> {
@@ -25,6 +30,7 @@
return ResponseEntity.ok().eTag(etag).build(body)
}
----
======
Spring MVC supports using a single value xref:web/webmvc/mvc-ann-async.adoc#mvc-ann-async-reactive-types[reactive type]
to produce the `ResponseEntity` asynchronously, and/or single and multi-value reactive

View File

@@ -8,14 +8,18 @@ If you need access to pre-existing session attributes that are managed globally
you can use the `@SessionAttribute` annotation on a method parameter,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RequestMapping("/")
public String handle(@SessionAttribute User user) { <1>
// ...
}
----
======
<1> Using a `@SessionAttribute` annotation.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]

View File

@@ -11,8 +11,11 @@ requests to access.
The following example uses the `@SessionAttributes` annotation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
@SessionAttributes("pet") // <1>
@@ -20,6 +23,7 @@ The following example uses the `@SessionAttributes` annotation:
// ...
}
----
======
<1> Using the `@SessionAttributes` annotation.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -38,8 +42,11 @@ it is automatically promoted to and saved in the HTTP Servlet session. It remain
until another controller method uses a `SessionStatus` method argument to clear the
storage, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
@SessionAttributes("pet") // <1>
@@ -57,6 +64,7 @@ storage, as the following example shows:
}
}
----
======
<1> Storing the `Pet` value in the Servlet session.
<2> Clearing the `Pet` value from the Servlet session.

View File

@@ -24,8 +24,11 @@ related to the request body.
The following example shows a `@ModelAttribute` method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
@@ -33,8 +36,10 @@ The following example shows a `@ModelAttribute` method:
// add more ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ModelAttribute
fun populateModel(@RequestParam number: String, model: Model) {
@@ -42,25 +47,32 @@ The following example shows a `@ModelAttribute` method:
// add more ...
}
----
======
The following example adds only one attribute:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountRepository.findAccount(number);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ModelAttribute
fun addAccount(@RequestParam number: String): Account {
return accountRepository.findAccount(number)
}
----
======
NOTE: When a name is not explicitly specified, a default name is chosen based on the `Object`
@@ -74,8 +86,11 @@ attribute. This is typically not required, as it is the default behavior in HTML
unless the return value is a `String` that would otherwise be interpreted as a view name.
`@ModelAttribute` can also customize the model attribute name, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
@@ -84,8 +99,10 @@ unless the return value is a `String` that would otherwise be interpreted as a v
return account;
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
@@ -94,6 +111,7 @@ unless the return value is a `String` that would otherwise be interpreted as a v
return account
}
----
======

View File

@@ -23,8 +23,11 @@ A `@RequestMapping` is still needed at the class level to express shared mapping
The following example has type and method level mappings:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@RestController
@RequestMapping("/persons")
@@ -42,8 +45,10 @@ The following example has type and method level mappings:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RestController
@RequestMapping("/persons")
@@ -61,6 +66,7 @@ The following example has type and method level mappings:
}
}
----
======
@@ -102,28 +108,37 @@ Some example patterns:
Captured URI variables can be accessed with `@PathVariable`. For example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
// ...
}
----
======
You can declare URI variables at the class and method levels, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Controller
@RequestMapping("/owners/{ownerId}")
@@ -135,8 +150,10 @@ You can declare URI variables at the class and method levels, as the following e
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
@RequestMapping("/owners/{ownerId}")
@@ -148,6 +165,7 @@ You can declare URI variables at the class and method levels, as the following e
}
}
----
======
URI variables are automatically converted to the appropriate type, or `TypeMismatchException`
is raised. Simple types (`int`, `long`, `Date`, and so on) are supported by default and you can
@@ -162,22 +180,28 @@ The syntax `{varName:regex}` declares a URI variable with a regular expression t
syntax of `{varName:regex}`. For example, given URL `"/spring-web-3.0.5.jar"`, the following method
extracts the name, version, and file extension:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
fun handle(@PathVariable name: String, @PathVariable version: String, @PathVariable ext: String) {
// ...
}
----
======
URI path patterns can also have embedded `${...}` placeholders that are resolved on startup
by using `PropertySourcesPlaceholderConfigurer` against local, system, environment, and
@@ -274,14 +298,18 @@ recommendations related to RFD.
You can narrow the request mapping based on the `Content-Type` of the request,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@PostMapping(path = "/pets", consumes = "application/json") // <1>
public void addPet(@RequestBody Pet pet) {
// ...
}
----
======
<1> Using a `consumes` attribute to narrow the mapping by the content type.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -312,8 +340,11 @@ TIP: `MediaType` provides constants for commonly used media types, such as
You can narrow the request mapping based on the `Accept` request header and the list of
content types that a controller method produces, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping(path = "/pets/{petId}", produces = "application/json") // <1>
@ResponseBody
@@ -321,6 +352,7 @@ content types that a controller method produces, as the following example shows:
// ...
}
----
======
<1> Using a `produces` attribute to narrow the mapping by the content type.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -353,14 +385,18 @@ You can narrow request mappings based on request parameter conditions. You can t
presence of a request parameter (`myParam`), for the absence of one (`!myParam`), or for a
specific value (`myParam=myValue`). The following example shows how to test for a specific value:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") // <1>
public void findPet(@PathVariable String petId) {
// ...
}
----
======
<1> Testing whether `myParam` equals `myValue`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -375,14 +411,18 @@ specific value (`myParam=myValue`). The following example shows how to test for
You can also use the same with request header conditions, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@GetMapping(path = "/pets/{petId}", headers = "myHeader=myValue") // <1>
public void findPet(@PathVariable String petId) {
// ...
}
----
======
<1> Testing whether `myHeader` equals `myValue`.
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -455,8 +495,11 @@ You can programmatically register handler methods, which you can use for dynamic
registrations or for advanced cases, such as different instances of the same handler
under different URLs. The following example registers a handler method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
public class MyConfig {
@@ -474,6 +517,7 @@ under different URLs. The following example registers a handler method:
}
}
----
======
<1> Inject the target handler and the handler mapping for controllers.
<2> Prepare the request mapping meta data.
<3> Get the handler method.

View File

@@ -12,8 +12,11 @@ annotated class, indicating its role as a web component.
To enable auto-detection of such `@Controller` beans, you can add component scanning to
your Java configuration, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
@ComponentScan("org.example.web")
@@ -22,8 +25,10 @@ your Java configuration, as the following example shows:
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
@ComponentScan("org.example.web")
@@ -32,6 +37,7 @@ your Java configuration, as the following example shows:
// ...
}
----
======
The following example shows the XML configuration equivalent of the preceding example: