Migrate to Asciidoctor Tabs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]
|
||||
====
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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>) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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:
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user