diff --git a/framework-docs/src/docs/asciidoc/data-access.adoc b/framework-docs/src/docs/asciidoc/data-access.adoc index f86087b48b..fb847f14cb 100644 --- a/framework-docs/src/docs/asciidoc/data-access.adoc +++ b/framework-docs/src/docs/asciidoc/data-access.adoc @@ -3480,6 +3480,7 @@ configure a `DataSource` in your Spring configuration file and then dependency-i that shared `DataSource` bean into your DAO classes. The `JdbcTemplate` is created in the setter for the `DataSource`. This leads to DAOs that resemble the following: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3504,6 +3505,7 @@ the setter for the `DataSource`. This leads to DAOs that resemble the following: // JDBC-backed implementations of the methods on the CorporateEventDao follow... } ---- +-- The following example shows the corresponding XML configuration: @@ -3540,6 +3542,7 @@ support for dependency injection. In this case, you can annotate the class with (which makes it a candidate for component-scanning) and annotate the `DataSource` setter method with `@Autowired`. The following example shows how to do so: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3574,6 +3577,7 @@ method with `@Autowired`. The following example shows how to do so: <1> Annotate the class with `@Repository`. <2> Constructor injection of the `DataSource`. <3> Create a new `JdbcTemplate` with the `DataSource`. +-- The following example shows the corresponding XML configuration: @@ -7077,6 +7081,7 @@ in your Spring configuration file and then dependency-inject that shared `ConnectionFactory` bean into your DAO classes. The `DatabaseClient` is created in the setter for the `ConnectionFactory`. This leads to DAOs that resemble the following: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -7101,12 +7106,14 @@ the setter for the `ConnectionFactory`. This leads to DAOs that resemble the fol // R2DBC-backed implementations of the methods on the CorporateEventDao follow... } ---- +-- An alternative to explicit configuration is to use component-scanning and annotation support for dependency injection. In this case, you can annotate the class with `@Component` (which makes it a candidate for component-scanning) and annotate the `ConnectionFactory` setter method with `@Autowired`. The following example shows how to do so: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -7141,6 +7148,7 @@ method with `@Autowired`. The following example shows how to do so: <1> Annotate the class with `@Component`. <2> Constructor injection of the `ConnectionFactory`. <3> Create a new `DatabaseClient` with the `ConnectionFactory`. +-- Regardless of which of the above template initialization styles you choose to use (or not), it is seldom necessary to create a new instance of a `DatabaseClient` class each diff --git a/framework-docs/src/docs/asciidoc/web/webflux-cors.adoc b/framework-docs/src/docs/asciidoc/web/webflux-cors.adoc index cb646d9ed6..f7744ab1f2 100644 --- a/framework-docs/src/docs/asciidoc/web/webflux-cors.adoc +++ b/framework-docs/src/docs/asciidoc/web/webflux-cors.adoc @@ -83,6 +83,7 @@ The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`] annotation enables cross-origin requests on annotated controller methods, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -121,6 +122,7 @@ following example shows: } } ---- +-- By default, `@CrossOrigin` allows: @@ -139,6 +141,7 @@ the `allowOriginPatterns` property may be used to match to a dynamic set of orig `@CrossOrigin` is supported at the class level, too, and inherited by all methods. The following example specifies a certain domain and sets `maxAge` to an hour: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -177,10 +180,12 @@ The following example specifies a certain domain and sets `maxAge` to an hour: } } ---- +-- You can use `@CrossOrigin` at both the class and the method level, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -226,6 +231,7 @@ as the following example shows: ---- <1> Using `@CrossOrigin` at the class level. <2> Using `@CrossOrigin` at the method level. +-- diff --git a/framework-docs/src/docs/asciidoc/web/webflux-functional.adoc b/framework-docs/src/docs/asciidoc/web/webflux-functional.adoc index 30970068d7..781a3f6b91 100644 --- a/framework-docs/src/docs/asciidoc/web/webflux-functional.adoc +++ b/framework-docs/src/docs/asciidoc/web/webflux-functional.adoc @@ -317,6 +317,7 @@ ServerResponse.ok().hint(Jackson2CodecSupport.JSON_VIEW_HINT, MyJacksonView::cla We can write a handler function as a lambda, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -328,6 +329,7 @@ HandlerFunction helloWorld = ---- val helloWorld = HandlerFunction { ServerResponse.ok().bodyValue("Hello World") } ---- +-- That is convenient, but in an application we need multiple functions, and multiple inline lambda's can get messy. @@ -335,6 +337,7 @@ Therefore, it is useful to group related handler functions together into a handl has a similar role as `@Controller` in an annotation-based application. For example, the following class exposes a reactive `Person` repository: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -409,6 +412,7 @@ Note that `PersonRepository.savePerson(Person)` is a suspending function with no <3> `getPerson` is a handler function that returns a single person, identified by the `id` path variable. We retrieve that `Person` from the repository and create a JSON response, if it is found. If it is not found, we return a 404 Not Found response. +-- [[webflux-fn-handler-validation]] diff --git a/framework-docs/src/docs/asciidoc/web/webflux-webclient.adoc b/framework-docs/src/docs/asciidoc/web/webflux-webclient.adoc index 30fef6b023..c93e112b93 100644 --- a/framework-docs/src/docs/asciidoc/web/webflux-webclient.adoc +++ b/framework-docs/src/docs/asciidoc/web/webflux-webclient.adoc @@ -156,6 +156,7 @@ application deployed as a WAR), you can declare a Spring-managed bean of type Netty global resources are shut down when the Spring `ApplicationContext` is closed, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -170,11 +171,13 @@ as the following example shows: @Bean fun reactorResourceFactory() = ReactorResourceFactory() ---- +-- You can also choose not to participate in the global Reactor Netty resources. However, in this mode, the burden is on you to ensure that all Reactor Netty client and server instances use shared resources, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -225,6 +228,7 @@ instances use shared resources, as the following example shows: <1> Create resources independent of global ones. <2> Use the `ReactorClientHttpConnector` constructor with resource factory. <3> Plug the connector into the `WebClient.Builder`. +-- [[webflux-client-builder-reactor-timeout]] @@ -375,6 +379,7 @@ The following example shows how to customize the JDK `HttpClient`: The following example shows how to customize Jetty `HttpClient` settings: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -395,6 +400,7 @@ The following example shows how to customize Jetty `HttpClient` settings: .clientConnector(JettyClientHttpConnector(httpClient)) .build(); ---- +-- By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`), which remain active until the process exits or `stop()` is called. @@ -404,6 +410,7 @@ ensure that the resources are shut down when the Spring `ApplicationContext` is declaring a Spring-managed bean of type `JettyResourceFactory`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -446,6 +453,7 @@ shows: ---- <1> Use the `JettyClientHttpConnector` constructor with resource factory. <2> Plug the connector into the `WebClient.Builder`. +-- diff --git a/framework-docs/src/docs/asciidoc/web/webflux.adoc b/framework-docs/src/docs/asciidoc/web/webflux.adoc index 98f888bb21..f56fd1e6e1 100644 --- a/framework-docs/src/docs/asciidoc/web/webflux.adoc +++ b/framework-docs/src/docs/asciidoc/web/webflux.adoc @@ -1474,6 +1474,7 @@ You can map requests by using glob patterns and wildcards: Captured URI variables can be accessed with `@PathVariable`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -1490,9 +1491,11 @@ Captured URI variables can be accessed with `@PathVariable`, as the following ex // ... } ---- +-- You can declare URI variables at the class and method levels, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -1524,6 +1527,7 @@ You can declare URI variables at the class and method levels, as the following e ---- <1> Class-level URI mapping. <2> Method-level URI mapping. +-- URI variables are automatically converted to the appropriate type or a `TypeMismatchException` @@ -1543,6 +1547,7 @@ The syntax `{varName:regex}` declares a URI variable with a regular expression t syntax: `{varName:regex}`. For example, given a URL of `/spring-web-3.0.5.jar`, the following method extracts the name, version, and file extension: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -1559,6 +1564,7 @@ extracts the name, version, and file extension: // ... } ---- +-- URI path patterns can also have embedded `${...}` placeholders that are resolved on startup through `PropertySourcesPlaceholderConfigurer` against local, system, environment, and @@ -2660,6 +2666,7 @@ content. The best way to handle a file upload form (for example, from a browser) is through data binding to a <>, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -2700,6 +2707,7 @@ as the following example shows: } ---- +-- You can also submit multipart requests from non-browser clients in a RESTful service scenario. The following example uses a file along with JSON: @@ -2726,6 +2734,7 @@ Content-Transfer-Encoding: 8bit You can access individual parts with `@RequestPart`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -2749,11 +2758,13 @@ You can access individual parts with `@RequestPart`, as the following example sh ---- <1> Using `@RequestPart` to get the metadata. <2> Using `@RequestPart` to get the file. +-- To deserialize the raw part content (for example, to JSON -- similar to `@RequestBody`), you can declare a concrete target `Object`, instead of `Part`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -2773,6 +2784,7 @@ you can declare a concrete target `Object`, instead of `Part`, as the following } ---- <1> Using `@RequestPart` to get the metadata. +-- You can use `@RequestPart` in combination with `jakarta.validation.Valid` or Spring's `@Validated` annotation, which causes Standard Bean Validation to be applied. Validation @@ -2781,6 +2793,7 @@ The exception contains a `BindingResult` with the error details and can also be in the controller method by declaring the argument with an async wrapper and then using error related operators: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -2798,10 +2811,12 @@ error related operators: // ... } ---- +-- To access all multipart data as a `MultiValueMap`, you can use `@RequestBody`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -2821,6 +2836,7 @@ as the following example shows: } ---- <1> Using `@RequestBody`. +-- ===== `PartEvent` @@ -3347,6 +3363,7 @@ do, except for `@ModelAttribute` (command object) arguments. Typically, they are with a `WebDataBinder` argument, for registrations, and a `void` return value. The following example uses the `@InitBinder` annotation: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3381,11 +3398,13 @@ The following example uses the `@InitBinder` annotation: // ... } ---- +-- Alternatively, when using a `Formatter`-based setup through a shared `FormattingConversionService`, you could re-use the same approach and register controller-specific `Formatter` instances, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3417,6 +3436,8 @@ controller-specific `Formatter` instances, as the following example shows: } ---- <1> Adding a custom formatter (a `DateFormatter`, in this case). +-- + [[webflux-ann-initbinder-model-design]] ==== Model Design @@ -3823,6 +3844,7 @@ Controllers can add explicit support for HTTP caching. We recommend doing so, si against conditional request headers. A controller can add an `ETag` and `Cache-Control` settings to a `ResponseEntity`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3856,6 +3878,7 @@ settings to a `ResponseEntity`, as the following example shows: .body(book) } ---- +-- The preceding example sends a 304 (NOT_MODIFIED) response with an empty body if the comparison to the conditional request headers indicates the content has not changed. Otherwise, the @@ -3864,6 +3887,7 @@ to the conditional request headers indicates the content has not changed. Otherw You can also make the check against conditional request headers in the controller, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -3903,6 +3927,7 @@ as the following example shows: <1> Application-specific calculation. <2> Response has been set to 304 (NOT_MODIFIED). No further processing. <3> Continue with request processing. +-- There are three variants for checking conditional requests against `eTag` values, `lastModified` values, or both. For conditional `GET` and `HEAD` requests, you can set the response to diff --git a/framework-docs/src/docs/asciidoc/web/webmvc-functional.adoc b/framework-docs/src/docs/asciidoc/web/webmvc-functional.adoc index 937cb19b97..83ea766ab5 100644 --- a/framework-docs/src/docs/asciidoc/web/webmvc-functional.adoc +++ b/framework-docs/src/docs/asciidoc/web/webmvc-functional.adoc @@ -290,6 +290,7 @@ allows you to send Strings, or other objects as JSON. For example: We can write a handler function as a lambda, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -302,6 +303,7 @@ HandlerFunction helloWorld = val helloWorld: (ServerRequest) -> ServerResponse = { ServerResponse.ok().body("Hello World") } ---- +-- That is convenient, but in an application we need multiple functions, and multiple inline lambda's can get messy. @@ -309,6 +311,7 @@ Therefore, it is useful to group related handler functions together into a handl has a similar role as `@Controller` in an annotation-based application. For example, the following class exposes a reactive `Person` repository: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -384,6 +387,7 @@ JSON. <3> `getPerson` is a handler function that returns a single person, identified by the `id` path variable. We retrieve that `Person` from the repository and create a JSON response, if it is found. If it is not found, we return a 404 Not Found response. +-- [[webmvc-fn-handler-validation]] diff --git a/framework-docs/src/docs/asciidoc/web/webmvc.adoc b/framework-docs/src/docs/asciidoc/web/webmvc.adoc index 5c6015a29b..46c2435b65 100644 --- a/framework-docs/src/docs/asciidoc/web/webmvc.adoc +++ b/framework-docs/src/docs/asciidoc/web/webmvc.adoc @@ -5144,6 +5144,7 @@ Controllers can add explicit support for HTTP caching. We recommended doing so, against conditional request headers. A controller can add an `ETag` header and `Cache-Control` settings to a `ResponseEntity`, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -5176,6 +5177,7 @@ settings to a `ResponseEntity`, as the following example shows: .body(book) } ---- +-- The preceding example sends a 304 (NOT_MODIFIED) response with an empty body if the comparison to the conditional request headers indicates that the content has not changed. Otherwise, the @@ -5184,6 +5186,7 @@ to the conditional request headers indicates that the content has not changed. O You can also make the check against conditional request headers in the controller, as the following example shows: +-- [source,java,indent=0,subs="verbatim,quotes",role="primary"] .Java ---- @@ -5223,6 +5226,7 @@ as the following example shows: <1> Application-specific calculation. <2> The response has been set to 304 (NOT_MODIFIED) -- no further processing. <3> Continue with the request processing. +-- There are three variants for checking conditional requests against `eTag` values, `lastModified`