Remove admonitions surrounding code snippets

This commit is contained in:
Brian Clozel
2018-11-26 23:15:55 +01:00
parent 8c768e48fa
commit 33cbe2e77a
29 changed files with 139 additions and 3191 deletions

View File

@@ -43,7 +43,6 @@ set of Spring XML configuration files to load.
Consider the following `<listener/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -51,11 +50,9 @@ Consider the following `<listener/>` configuration:
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
----
====
Further consider the following `<context-param/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -64,7 +61,6 @@ Further consider the following `<context-param/>` configuration:
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
----
====
If you do not specify the `contextConfigLocation` context parameter, the
`ContextLoaderListener` looks for a file called `/WEB-INF/applicationContext.xml` to
@@ -79,13 +75,11 @@ created by the `ContextLoaderListener`.
The following example shows how to get the `WebApplicationContext`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
----
====
The
{api-spring-framework}/web/context/support/WebApplicationContextUtils.html[`WebApplicationContextUtils`]
@@ -140,7 +134,6 @@ implementation.
Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
`faces-context.xml` file, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -151,7 +144,6 @@ Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
</application>
</faces-config>
----
====
@@ -166,13 +158,11 @@ takes a `FacesContext` parameter rather than a `ServletContext` parameter.
The following example shows how to use `FacesContextUtils`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
----
====

View File

@@ -4,7 +4,6 @@
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -21,12 +20,11 @@
<3> Request to have the URI template and URI variables encoded.
<4> Build a `UriComponents`.
<5> Expand variables and obtain the `URI`.
====
The preceding example can be consolidated into one chain and shortened with `buildAndExpand`,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -37,12 +35,10 @@ as the following example shows:
.buildAndExpand("Westin", "123")
.toUri();
----
====
You can shorten it further by going directly to a URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -51,11 +47,9 @@ as the following example shows:
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
You shorter it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -63,7 +57,6 @@ You shorter it further still with a full URI template, as the following example
.fromUriString("http://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
----
====
@@ -83,7 +76,6 @@ exposes shared configuration options.
The following example shows how to configure a `RestTemplate`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -96,11 +88,9 @@ The following example shows how to configure a `RestTemplate`:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
----
====
The following example configures a `WebClient`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -112,13 +102,11 @@ The following example configures a `WebClient`:
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
In addition, you can also use `DefaultUriBuilderFactory` directly. It is similar to using
`UriComponentsBuilder` but, instead of static factory methods, it is an actual instance
that holds configuration and preferences, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -129,7 +117,6 @@ that holds configuration and preferences, as the following example shows:
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
@@ -157,7 +144,6 @@ URI variables intentionally contain reserved characters.
The following example uses the first option:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -169,12 +155,10 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"
----
====
You can shorten the preceding example by going directly to the URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -182,24 +166,20 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
----
====
You can shorten it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
----
====
The `WebClient` and the `RestTemplate` expand and encode URI templates internally through
the `UriBuilderFactory` strategy. Both can be configured with a custom strategy.
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -214,7 +194,6 @@ as the following example shows:
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
The `DefaultUriBuilderFactory` implementation uses `UriComponentsBuilder` internally to
expand and encode URI templates. As a factory, it provides a single place to configure

View File

@@ -83,7 +83,6 @@ 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"]
----
@@ -103,7 +102,6 @@ public class AccountController {
}
}
----
====
By default, `@CrossOrigin` allows:
@@ -121,7 +119,6 @@ should be used only where appropriate.
`@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"]
----
@@ -141,11 +138,9 @@ public class AccountController {
}
}
----
====
You can use `@CrossOrigin` at both the class and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
@@ -169,8 +164,6 @@ public class AccountController {
----
<1> Using `@CrossOrigin` at the class level.
<2> Using `@CrossOrigin` at the method level.
====
@@ -198,7 +191,6 @@ should be used only where appropriate.
To enable CORS in the WebFlux Java configuration, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -220,7 +212,6 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
@@ -236,7 +227,6 @@ good fit with <<webflux-fn,functional endpoints>>.
To configure the filter, you can declare a `CorsWebFilter` bean and pass a
`CorsConfigurationSource` to its constructor, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim"]
----
@@ -259,4 +249,3 @@ CorsWebFilter corsFilter() {
return new CorsWebFilter(source);
}
----
====

View File

@@ -28,7 +28,6 @@ difference that router functions provide not just data, but also behavior.
`RouterFunctions.route()` provides a router builder that facilitates the creation of routers,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -63,7 +62,6 @@ public class PersonHandler {
}
}
----
====
One way to run a `RouterFunction` is to turn it into an `HttpHandler` and install it
through one of the built-in <<web-reactive.adoc#webflux-httphandler,server adapters>>:
@@ -97,62 +95,50 @@ while access to the body is provided through the `body` methods.
The following example extracts the request body to a `Mono<String>`:
====
[source,java]
----
Mono<String> string = request.bodyToMono(String.class);
----
====
The following example extracts the body to a `Flux<Person>`, where `Person` objects are decoded from some
serialized form, such as JSON or XML:
====
[source,java]
----
Flux<Person> people = request.bodyToFlux(Person.class);
----
====
The preceding examples are shortcuts that use the more general `ServerRequest.body(BodyExtractor)`,
which accepts the `BodyExtractor` functional strategy interface. The utility class
`BodyExtractors` provides access to a number of instances. For example, the preceding examples can
also be written as follows:
====
[source,java]
----
Mono<String> string = request.body(BodyExtractors.toMono(String.class));
Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class));
----
====
The following example shows how to access form data:
====
[source,java]
----
Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData());
----
====
The following example shows how to access multipart data as a map:
====
[source,java]
----
Mono<MultiValueMap<String, Part> map = request.body(BodyExtractors.toMultipartData());
----
====
The following example shows how to access multiparts, one at a time, in streaming fashion:
====
[source,java]
----
Flux<Part> parts = request.body(BodyExtractos.toParts());
----
====
@@ -164,23 +150,19 @@ a `build` method to create it. You can use the builder to set the response statu
headers, or to provide a body. The following example creates a 200 (OK) response with JSON
content:
====
[source,java]
----
Mono<Person> person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);
----
====
The following example shows how to build a 201 (CREATED) response with a `Location` header and no body:
====
[source,java]
----
URI location = ...
ServerResponse.created(location).build();
----
====
@@ -189,14 +171,12 @@ ServerResponse.created(location).build();
We can write a handler function as a lambda, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
HandlerFunction<ServerResponse> helloWorld =
request -> ServerResponse.ok().body(fromObject("Hello World"));
----
====
That is convenient, but in an application we need multiple functions, and multiple inline
lambda's can get messy.
@@ -204,7 +184,6 @@ 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"]
----
@@ -248,7 +227,6 @@ when the `Person` has been saved).
<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 use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
====
@@ -324,7 +302,6 @@ and so on.
The following example uses a request predicate to create a constraint based on the `Accept`
header:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -332,7 +309,6 @@ RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/hello-world", accept(MediaType.TEXT_PLAIN),
request -> Response.ok().body(fromObject("Hello World")));
----
====
You can compose multiple request predicates together by using:
@@ -368,7 +344,6 @@ There are also other ways to compose multiple router functions together:
The following example shows the composition of four routes:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -395,7 +370,6 @@ RouterFunction<ServerResponse> route = route()
`PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
====
=== Nested Routes
@@ -409,7 +383,6 @@ When using annotations, you would remove this duplication by using a type-level
In WebFlux.fn, path predicates can be shared through the `path` method on the router function builder.
For instance, the last few lines of the example above can be improved in the following way by using nested routes:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -420,7 +393,6 @@ RouterFunction<ServerResponse> route = route()
.POST("/person", handler::createPerson))
.build();
----
====
Note that second parameter of `path` is a consumer that takes the a router builder.
@@ -429,7 +401,6 @@ the `nest` method on the builder.
The above still contains some duplication in the form of the shared `Accept`-header predicate.
We can further improve by using the `nest` method together with `accept`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -441,7 +412,6 @@ RouterFunction<ServerResponse> route = route()
.POST("/person", handler::createPerson))
.build();
----
====
[[webflux-fn-running]]
@@ -478,7 +448,6 @@ starter.
The following example shows a WebFlux Java configuration (see
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run it):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -514,7 +483,6 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
@@ -529,7 +497,6 @@ The filter will apply to all routes that are built by the builder.
This means that filters defined in nested routes do not apply to "top-level" routes.
For instance, consider the following example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -547,7 +514,7 @@ RouterFunction<ServerResponse> route = route()
----
<1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones.
====
The `filter` method on the router builder takes a `HandlerFilterFunction`: a
function that takes a `ServerRequest` and `HandlerFunction` and returns a `ServerResponse`.
@@ -559,7 +526,6 @@ Now we can add a simple security filter to our route, assuming that we have a `S
can determine whether a particular path is allowed.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -582,7 +548,6 @@ RouterFunction<ServerResponse> route = route()
})
.build();
----
====
The preceding example demonstrates that invoking the `next.handle(ServerRequest)` is optional.
We allow only the handler function to be executed when access is allowed.

View File

@@ -47,7 +47,6 @@ integration for using Spring WebFlux with FreeMarker templates.
The following example shows how to configure FreeMarker as a view technology:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -70,7 +69,6 @@ The following example shows how to configure FreeMarker as a view technology:
}
}
----
====
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`,
shown in the preceding example. Given the preceding configuration, if your controller returns the view name,
@@ -89,7 +87,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
`java.util.Properties` object, and the `freemarkerVariables` property requires a
`java.util.Map`. The following example shows how to use a `FreeMarkerConfigurer`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -111,7 +108,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
}
}
----
====
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
@@ -173,7 +169,6 @@ You can declare a `ScriptTemplateConfigurer` bean to specify the script engine t
the script files to load, what function to call to render templates, and so on.
The following example uses Mustache templates and the Nashorn JavaScript engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -197,7 +192,6 @@ The following example uses Mustache templates and the Nashorn JavaScript engine:
}
}
----
====
The `render` function is called with the following parameters:
@@ -217,7 +211,6 @@ http://en.wikipedia.org/wiki/Polyfill[polyfill] in order to emulate some
browser facilities not available in the server-side script engine.
The following example shows how to set a custom render function:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -241,7 +234,6 @@ The following example shows how to set a custom render function:
}
}
----
====
NOTE: Setting the `sharedEngine` property to `false` is required when using non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
@@ -251,13 +243,11 @@ to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
`polyfill.js` defines only the `window` object needed by Handlebars to run properly,
as the following snippet shows:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
====
This basic `render.js` implementation compiles the template before using it. A production
ready implementation should also store and reused cached templates or pre-compiled templates.
@@ -265,7 +255,6 @@ This can be done on the script side, as well as any customization you need (mana
template engine configuration for example).
The following example shows how compile a template:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@@ -274,7 +263,6 @@ The following example shows how compile a template:
return compiledTemplate(model);
}
----
====
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[Java], and

View File

@@ -38,7 +38,6 @@ You can also use `WebClient.builder()` with further options:
The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -52,12 +51,10 @@ The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>
.exchangeStrategies(strategies)
.build();
----
====
Once built, a `WebClient` instance is immutable. However, you can clone it and build a
modified copy without affecting the original instance, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -71,7 +68,6 @@ modified copy without affecting the original instance, as the following example
// client2 has filterA, filterB, filterC, filterD
----
====
@@ -80,7 +76,6 @@ modified copy without affecting the original instance, as the following example
To customize Reactor Netty settings, simple provide a pre-configured `HttpClient`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -90,7 +85,6 @@ To customize Reactor Netty settings, simple provide a pre-configured `HttpClient
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
----
====
[[webflux-client-builder-reactor-resources]]
@@ -108,7 +102,6 @@ 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,intent=0]
[subs="verbatim,quotes"]
----
@@ -117,13 +110,11 @@ as the following example shows:
return new 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,intent=0]
[subs="verbatim,quotes"]
----
@@ -150,7 +141,6 @@ 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]]
@@ -158,7 +148,6 @@ instances use shared resources, as the following example shows:
To configure a connection timeout:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -168,11 +157,9 @@ HttpClient httpClient = HttpClient.create()
.tcpConfiguration(client ->
client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000));
----
====
To configure a read and/or write timeout values:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -185,7 +172,6 @@ HttpClient httpClient = HttpClient.create()
.addHandlerLast(new ReadTimeoutHandler(10))
.addHandlerLast(new WriteTimeoutHandler(10))));
----
====
@@ -194,7 +180,6 @@ HttpClient httpClient = HttpClient.create()
The following example shows how to customize Jetty `HttpClient` settings:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -204,7 +189,6 @@ The following example shows how to customize Jetty `HttpClient` settings:
WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
====
By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`),
which remain active until the process exits or `stop()` is called.
@@ -214,7 +198,6 @@ 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,intent=0]
[subs="verbatim,quotes"]
----
@@ -238,7 +221,6 @@ shows:
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.
====
@@ -249,7 +231,6 @@ shows:
The `retrieve()` method is the easiest way to get a response body and decode it.
The following example shows how to do so:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -260,11 +241,9 @@ The following example shows how to do so:
.retrieve()
.bodyToMono(Person.class);
----
====
You can also get a stream of objects decoded from the response, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -273,7 +252,6 @@ You can also get a stream of objects decoded from the response, as the following
.retrieve()
.bodyToFlux(Quote.class);
----
====
By default, responses with 4xx or 5xx status codes result in an
`WebClientResponseException` or one of its HTTP status specific sub-classes, such as
@@ -281,7 +259,6 @@ By default, responses with 4xx or 5xx status codes result in an
You can also use the `onStatus` method to customize the resulting exception,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -292,7 +269,6 @@ as the following example shows:
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(Person.class);
----
====
When `onStatus` is used, if the response is expected to have content, then the `onStatus`
callback should consume it. If not, the content will be automatically drained to ensure
@@ -307,7 +283,6 @@ resources are released.
The `exchange()` method provides more control than the `retrieve` method. The following example is equivalent
to `retrieve()` but also provides access to the `ClientResponse`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -316,11 +291,9 @@ to `retrieve()` but also provides access to the `ClientResponse`:
.exchange()
.flatMap(response -> response.bodyToMono(Person.class));
----
====
At this level, you can also create a full `ResponseEntity`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -329,7 +302,6 @@ At this level, you can also create a full `ResponseEntity`:
.exchange()
.flatMap(response -> response.toEntity(Person.class));
----
====
Note that (unlike `retrieve()`), with `exchange()`, there are no automatic error signals for
4xx and 5xx responses. You have to check the status code and decide how to proceed.
@@ -348,7 +320,6 @@ is closed and is not placed back in the pool.
The request body can be encoded from an `Object`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -361,11 +332,9 @@ The request body can be encoded from an `Object`, as the following example shows
.retrieve()
.bodyToMono(Void.class);
----
====
You can also have a stream of objects be encoded, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -378,12 +347,10 @@ You can also have a stream of objects be encoded, as the following example shows
.retrieve()
.bodyToMono(Void.class);
----
====
Alternatively, if you have the actual value, you can use the `syncBody` shortcut method,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -396,7 +363,6 @@ as the following example shows:
.retrieve()
.bodyToMono(Void.class);
----
====
@@ -407,7 +373,6 @@ To send form data, you can provide a `MultiValueMap<String, String>` as the body
content is automatically set to `application/x-www-form-urlencoded` by the
`FormHttpMessageWriter`. The following example shows how to use `MultiValueMap<String, String>`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -419,11 +384,9 @@ content is automatically set to `application/x-www-form-urlencoded` by the
.retrieve()
.bodyToMono(Void.class);
----
====
You can also supply form data in-line by using `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -435,7 +398,6 @@ You can also supply form data in-line by using `BodyInserters`, as the following
.retrieve()
.bodyToMono(Void.class);
----
====
@@ -467,7 +429,6 @@ builder `part` methods.
Once a `MultiValueMap` is prepared, the easiest way to pass it to the the `WebClient` is
through the `syncBody` method, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -479,7 +440,6 @@ through the `syncBody` method, as the following example shows:
.retrieve()
.bodyToMono(Void.class);
----
====
If the `MultiValueMap` contains at least one non-`String` value, which could also
represent regular form data (that is, `application/x-www-form-urlencoded`), you need not
@@ -489,7 +449,6 @@ set the `Content-Type` to `multipart/form-data`. This is always the case when us
As an alternative to `MultipartBodyBuilder`, you can also provide multipart content,
inline-style, through the built-in `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -501,7 +460,6 @@ inline-style, through the built-in `BodyInserters`, as the following example sho
.retrieve()
.bodyToMono(Void.class);
----
====
@@ -512,7 +470,6 @@ inline-style, through the built-in `BodyInserters`, as the following example sho
You can register a client filter (`ExchangeFilterFunction`) through the `WebClient.Builder`
in order to intercept and modify requests, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -527,12 +484,10 @@ WebClient client = WebClient.builder()
})
.build();
----
====
This can be used for cross-cutting concerns, such as authentication. The following example uses
a filter for basic authentication through a static factory method:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -543,13 +498,11 @@ WebClient client = WebClient.builder()
.filter(basicAuthentication("user", "password"))
.build();
----
====
Filters apply globally to every request. To change a filter's behavior for a specific
request, you can add request attributes to the `ClientRequest` that can then be accessed
by all filters in the chain, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -567,13 +520,11 @@ client.get().uri("http://example.org/")
}
----
====
You can also replicate an existing `WebClient`, insert new filters, or remove already
registered filters. The following example, inserts a basic authentication filter at
index 0:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@@ -586,7 +537,6 @@ WebClient client = webClient.mutate()
})
.build();
----
====

View File

@@ -26,7 +26,6 @@ server-side applications that handle WebSocket messages.
To create a WebSocket server, you can first create a `WebSocketHandler`.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -41,11 +40,9 @@ The following example shows how to do so:
}
}
----
====
Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -69,7 +66,6 @@ Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the followi
}
}
----
====
@@ -110,7 +106,6 @@ receives a cancellation signal.
The most basic implementation of a handler is one that handles the inbound stream. The
following example shows such an implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -133,7 +128,7 @@ class ExampleHandler implements WebSocketHandler {
<2> Do something with each message.
<3> Perform nested asynchronous operations that use the message content.
<4> Return a `Mono<Void>` that completes when receiving completes.
====
TIP: For nested, asynchronous operations, you may need to call `message.retain()` on underlying
servers that use pooled data buffers (for example, Netty). Otherwise, the data buffer may be
@@ -142,7 +137,6 @@ released before you have had a chance to read the data. For more background, see
The following implementation combines the inbound and outbound streams:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -167,12 +161,11 @@ class ExampleHandler implements WebSocketHandler {
<1> Handle the inbound message stream.
<2> Create the outbound message, producing a combined flow.
<3> Return a `Mono<Void>` that does not complete while we continue to receive.
====
Inbound and outbound streams can be independent and be joined only for completion,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -200,7 +193,6 @@ class ExampleHandler implements WebSocketHandler {
<1> Handle inbound message stream.
<2> Send outgoing messages.
<3> Join the streams and return a `Mono<Void>` that completes when either stream ends.
====
@@ -243,7 +235,6 @@ The `RequestUpgradeStrategy` for each server exposes WebSocket-related configura
options available for the underlying WebSocket engine. The following example sets
WebSocket options when running on Tomcat:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -263,7 +254,6 @@ WebSocket options when running on Tomcat:
}
}
----
====
Check the upgrade strategy for your server to see what options are available. Currently,
only Tomcat and Jetty expose such options.
@@ -296,7 +286,6 @@ API to suspend receiving messages for back pressure.
To start a WebSocket session, you can create an instance of the client and use its `execute`
methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -308,7 +297,6 @@ client.execute(url, session ->
.doOnNext(System.out::println)
.then());
----
====
Some clients, such as Jetty, implement `Lifecycle` and need to be stopped and started
before you can use them. All clients have constructor options related to configuration

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,6 @@ 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"]
----
@@ -103,7 +102,6 @@ public class AccountController {
}
}
----
====
By default, `@CrossOrigin` allows:
@@ -120,7 +118,6 @@ should only be used where appropriate.
`@CrossOrigin` is supported at the class level, too, and is inherited by all methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -140,12 +137,10 @@ public class AccountController {
}
}
----
====
You can use `@CrossOrigin` at both the class level and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -166,7 +161,6 @@ public class AccountController {
}
}
----
====
@@ -202,7 +196,6 @@ should only be used where appropriate.
To enable CORS in the MVC Java config, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -224,7 +217,6 @@ public class WebConfig implements WebMvcConfigurer {
}
}
----
====
@@ -234,7 +226,6 @@ public class WebConfig implements WebMvcConfigurer {
To enable CORS in the XML namespace, you can use the `<mvc:cors>` element,
as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@@ -252,7 +243,6 @@ as the following example shows:
</mvc:cors>
----
====
@@ -272,7 +262,6 @@ for CORS.
To configure the filter, pass a
`CorsConfigurationSource` to its constructor, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim"]
----
@@ -291,4 +280,3 @@ source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);
----
====

View File

@@ -46,7 +46,6 @@ integration for using Spring MVC with FreeMarker templates.
The following example shows how to configure FreeMarker as a view technology:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -69,11 +68,9 @@ The following example shows how to configure FreeMarker as a view technology:
}
}
----
====
The following example shows how to configure the same in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -88,12 +85,10 @@ The following example shows how to configure the same in XML:
<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
----
====
Alternatively, you can also declare the `FreeMarkerConfigurer` bean for full control over all
properties, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -101,7 +96,6 @@ properties, as the following example shows:
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
----
====
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`
shown in the preceding example. Given the preceding configuration, if your controller returns a view name
@@ -119,7 +113,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
`java.util.Properties` object, and the `freemarkerVariables` property requires a
`java.util.Map`. The following example shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -134,7 +127,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
----
====
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
@@ -173,7 +165,6 @@ controller, you can use code similar to the next example to bind to field values
display error messages for each input field in similar fashion to the JSP equivalent.
The following example shows the `personForm` view that was configured earlier:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -196,7 +187,6 @@ The following example shows the `personForm` view that was configured earlier:
...
</html>
----
====
`<@spring.bind>` requires a 'path' argument, which consists of the name of your command
object (it is 'command', unless you changed it in your `FormController` properties)
@@ -318,14 +308,12 @@ time, a class name or style attribute. Note that FreeMarker can specify default
values for the attributes parameter. The following example shows how to use the `formInput`
and `showWErrors` macros:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>
----
====
The next example shows the output of the form fragment, generating the name field and displaying a
validation error after the form was submitted with no value in the field. Validation
@@ -333,7 +321,6 @@ occurs through Spring's Validation framework.
The generated HTML resembles the following example:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@@ -344,7 +331,6 @@ The generated HTML resembles the following example:
<br>
<br>
----
====
The `formTextarea` macro works the same way as the `formInput` macro and accepts the same
parameter list. Commonly, the second parameter (attributes) is used to pass style
@@ -370,7 +356,6 @@ value of 'London' for this field, so no validation is necessary. When the form i
rendered, the entire list of cities to choose from is supplied as reference data in the
model under the name 'cityMap'. The following listing shows the example:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@@ -378,7 +363,6 @@ model under the name 'cityMap'. The following listing shows the example:
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>
----
====
The preceding listing renders a line of radio buttons, one for each value in `cityMap`, and uses a
separator of `""`. No additional attributes are supplied (the last parameter to the macro is
@@ -387,7 +371,6 @@ keys are what the form actually submits as POSTed request parameters. The map va
labels that the user sees. In the preceding example, given a list of three well known cities
and a default value in the form backing object, the HTML resembles the following:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@@ -396,12 +379,10 @@ and a default value in the form backing object, the HTML resembles the following
<input type="radio" name="address.town" value="Paris" checked="checked">Paris</input>
<input type="radio" name="address.town" value="New York">New York</input>
----
====
If your application expects to handle cities by internal codes (for example), you can create the map of
codes with suitable keys, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -416,12 +397,10 @@ codes with suitable keys, as the following example shows:
return model;
}
----
====
The code now produces output where the radio values are the relevant codes, but the
user still sees the more user-friendly city names, as follows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@@ -430,7 +409,6 @@ user still sees the more user-friendly city names, as follows:
<input type="radio" name="address.town" value="PRS" checked="checked">Paris</input>
<input type="radio" name="address.town" value="NYC">New York</input>
----
====
[[mvc-views-form-macros-html-escaping]]
@@ -447,21 +425,18 @@ template processing to provide different behavior for different fields in your f
To switch to XHTML compliance for your tags, specify a value of `true` for a
model or context variable named `xhtmlCompliant`, as the following example shows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
<#-- for FreeMarker -->
<#assign xhtmlCompliant = true>
----
====
After processing
this directive, any elements generated by the Spring macros are now XHTML compliant.
In similar fashion, you can specify HTML escaping per field, as the following example shows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@@ -474,7 +449,6 @@ In similar fashion, you can specify HTML escaping per field, as the following ex
<#assign htmlEscape = false in spring>
<#-- all future fields will be bound with HTML escaping off -->
----
====
@@ -496,7 +470,6 @@ NOTE: The Groovy Markup Template engine requires Groovy 2.3.1+.
The following example shows how to configure the Groovy Markup Template Engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -519,11 +492,9 @@ The following example shows how to configure the Groovy Markup Template Engine:
}
}
----
====
The following example shows how to configure the same in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -536,7 +507,6 @@ The following example shows how to configure the same in XML:
<!-- Configure the Groovy Markup Template Engine... -->
<mvc:groovy-configurer resource-loader-path="/WEB-INF/"/>
----
====
@@ -546,7 +516,6 @@ The following example shows how to configure the same in XML:
Unlike traditional template engines, Groovy Markup relies on a DSL that uses a builder
syntax. The following example shows a sample template for an HTML page:
====
[source,groovy,indent=0]
[subs="verbatim,quotes"]
----
@@ -561,7 +530,6 @@ syntax. The following example shows a sample template for an HTML page:
}
}
----
====
@@ -620,7 +588,6 @@ You can declare a `ScriptTemplateConfigurer` bean to specify the script engine t
the script files to load, what function to call to render templates, and so on.
The following example uses Mustache templates and the Nashorn JavaScript engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -644,11 +611,9 @@ The following example uses Mustache templates and the Nashorn JavaScript engine:
}
}
----
====
The following example shows the same arrangement in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -662,11 +627,9 @@ The following example shows the same arrangement in XML:
<mvc:script location="mustache.js"/>
</mvc:script-template-configurer>
----
====
The controller would look no different for the Java and XML configurations, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -681,11 +644,9 @@ The controller would look no different for the Java and XML configurations, as t
}
}
----
====
The following example shows the Mustache template:
====
[source,html,indent=0]
[subs="verbatim,quotes"]
----
@@ -698,7 +659,6 @@ The following example shows the Mustache template:
</body>
</html>
----
====
The render function is called with the following parameters:
@@ -719,7 +679,6 @@ browser facilities that are not available in the server-side script engine.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -743,7 +702,6 @@ The following example shows how to do so:
}
}
----
====
NOTE: Setting the `sharedEngine` property to `false` is required when you use non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
@@ -752,20 +710,17 @@ to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
`polyfill.js` defines only the `window` object needed by Handlebars to run properly, as follows:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
====
This basic `render.js` implementation compiles the template before using it. A production-ready
implementation should also store any reused cached templates or pre-compiled templates.
You can do so on the script side (and handle any customization you need -- managing
template engine configuration, for example). The following example shows how to do so:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@@ -774,7 +729,6 @@ template engine configuration, for example). The following example shows how to
return compiledTemplate(model);
}
----
====
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script[Java], and
@@ -801,7 +755,6 @@ When developing with JSPs, you can declare a `InternalResourceViewResolver` or a
mapped to a class and a URL. With a `ResourceBundleViewResolver`, you
can mix different types of views byusing only one resolver, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -831,7 +784,6 @@ directory so there can be no direct access by clients.
<property name="suffix" value=".jsp"/>
</bean>
----
====
@@ -884,14 +836,12 @@ called `spring-form.tld`.
To use the tags from this library, add the following directive to the top of your JSP
page:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
----
where `form` is the tag name prefix you want to use for the tags from this library.
====
[[mvc-view-jsp-formtaglib-formtag]]
@@ -907,7 +857,6 @@ such as `firstName` and `lastName`. We can use it as the form-backing object of
form controller, which returns `form.jsp`. The following example shows what `form.jsp` could
look like:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -929,7 +878,6 @@ look like:
</table>
</form:form>
----
====
The `firstName` and `lastName` values are retrieved from the command object placed in
the `PageContext` by the page controller. Keep reading to see more complex examples of
@@ -937,7 +885,6 @@ how inner tags are used with the `form` tag.
The following listing shows the generated HTML, which looks like a standard form:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -959,14 +906,12 @@ The following listing shows the generated HTML, which looks like a standard form
</table>
</form>
----
====
The preceding JSP assumes that the variable name of the form-backing object is
`command`. If you have put the form-backing object into the model under another name
(definitely a best practice), you can bind the form to the named variable, as the
following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -988,7 +933,6 @@ following example shows:
</table>
</form:form>
----
====
[[mvc-view-jsp-formtaglib-inputtag]]
@@ -1008,7 +952,6 @@ This tag renders an HTML `input` tag with the `type` set to `checkbox`.
Assume that our `User` has preferences such as newsletter subscription and a list of
hobbies. The following example shows the `Preferences` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1043,11 +986,9 @@ hobbies. The following example shows the `Preferences` class:
}
}
----
====
The corresponding `form.jsp` could then resemble the following:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1079,7 +1020,6 @@ The corresponding `form.jsp` could then resemble the following:
</table>
</form:form>
----
====
There are three approaches to the `checkbox` tag, which should meet all your checkbox needs.
@@ -1095,7 +1035,6 @@ There are three approaches to the `checkbox` tag, which should meet all your che
Note that, regardless of the approach, the same HTML structure is generated. The following
HTML snippet defines some checkboxes:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1111,7 +1050,6 @@ HTML snippet defines some checkboxes:
</td>
</tr>
----
====
You might not expect to see the additional hidden field after each checkbox.
When a checkbox in an HTML page is not checked, its value is not sent to the
@@ -1137,7 +1075,6 @@ the available options in the `items` property. Typically, the bound property is
collection so that it can hold multiple values selected by the user. The following example
shows a JSP that uses this tag:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1153,7 +1090,6 @@ shows a JSP that uses this tag:
</table>
</form:form>
----
====
This example assumes that the `interestList` is a `List` available as a model attribute
that contains strings of the values to be selected from. If you use a `Map`,
@@ -1171,7 +1107,6 @@ This tag renders an HTML `input` element with the `type` set to `radio`.
A typical usage pattern involves multiple tag instances bound to the same property
but with different values, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1183,7 +1118,6 @@ but with different values, as the following example shows:
</td>
</tr>
----
====
@@ -1200,7 +1134,6 @@ entry's value are used as the label to be displayed. You can also use a custom
object where you can provide the property names for the value by using `itemValue` and the
label by using `itemLabel`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1209,7 +1142,6 @@ label by using `itemLabel`, as the following example shows:
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-passwordtag]]
@@ -1217,7 +1149,6 @@ label by using `itemLabel`, as the following example shows:
This tag renders an HTML `input` tag with the type set to `password` with the bound value.
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1228,13 +1159,11 @@ This tag renders an HTML `input` tag with the type set to `password` with the bo
</td>
</tr>
----
====
Note that, by default, the password value is not shown. If you do want the
password value to be shown, you can set the value of the `showPassword` attribute to
`true`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1245,7 +1174,6 @@ password value to be shown, you can set the value of the `showPassword` attribut
</td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-selecttag]]
@@ -1256,7 +1184,6 @@ option as well as the use of nested `option` and `options` tags.
Assume that a `User` has a list of skills. The corresponding HTML could be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1265,12 +1192,10 @@ Assume that a `User` has a list of skills. The corresponding HTML could be as fo
<td><form:select path="skills" items="${skills}"/></td>
</tr>
----
====
If the `User's` skill are in Herbology, the HTML source of the 'Skills' row could be
as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1285,7 +1210,6 @@ as follows:
</td>
</tr>
----
====
@@ -1295,7 +1219,6 @@ as follows:
This tag renders an HTML `option` element. It sets `selected`, based on the bound
value. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1311,12 +1234,10 @@ value. The following HTML shows typical output for it:
</td>
</tr>
----
====
If the `User's` house was in Gryffindor, the HTML source of the 'House' row would be
as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1333,7 +1254,6 @@ as follows:
</tr>
----
<1> Note the addition of a `selected` attribute.
====
@@ -1343,7 +1263,6 @@ as follows:
This tag renders a list of HTML `option` elements. It sets the `selected` attribute,
based on the bound value. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1357,11 +1276,9 @@ based on the bound value. The following HTML shows typical output for it:
</td>
</tr>
----
====
If the `User` lived in the UK, the HTML source of the 'Country' row would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1378,7 +1295,7 @@ If the `User` lived in the UK, the HTML source of the 'Country' row would be as
</tr>
----
<1> Note the addition of a `selected` attribute.
====
As the preceding example shows, the combined usage of an `option` tag with the `options` tag
generates the same standard HTML but lets you explicitly specify a value in the
@@ -1400,7 +1317,6 @@ the item label property applies to the map value.
This tag renders an HTML `textarea` element. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1410,7 +1326,6 @@ This tag renders an HTML `textarea` element. The following HTML shows typical ou
<td><form:errors path="notes"/></td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-hiddeninputtag]]
@@ -1420,24 +1335,20 @@ This tag renders an HTML `input` tag with the `type` set to `hidden` with the bo
an unbound hidden value, use the HTML `input` tag with the `type` set to `hidden`.
The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<form:hidden path="house"/>
----
====
If we choose to submit the `house` value as a hidden one, the HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<input name="house" type="hidden" value="Gryffindor"/>
----
====
[[mvc-view-jsp-formtaglib-errorstag]]
@@ -1451,7 +1362,6 @@ Assume that we want to display all error messages for the `firstName` and `lastN
fields once we submit the form. We have a validator for instances of the `User` class
called `UserValidator`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1467,11 +1377,9 @@ called `UserValidator`, as the following example shows:
}
}
----
====
The `form.jsp` could be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1498,12 +1406,10 @@ The `form.jsp` could be as follows:
</table>
</form:form>
----
====
If we submit a form with empty values in the `firstName` and `lastName` fields,
the HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1530,7 +1436,6 @@ the HTML would be as follows:
</table>
</form>
----
====
What if we want to display the entire list of errors for a given page? The next example
shows that the `errors` tag also supports some basic wildcarding functionality.
@@ -1542,7 +1447,6 @@ shows that the `errors` tag also supports some basic wildcarding functionality.
The following example displays a list of errors at the top of the page, followed by
field-specific errors next to the fields:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1567,11 +1471,9 @@ field-specific errors next to the fields:
</table>
</form:form>
----
====
The HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1597,7 +1499,6 @@ The HTML would be as follows:
</table>
</form>
----
====
The `spring-form.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`.
For a comprehensive reference on individual tags, browse the
@@ -1628,7 +1529,6 @@ To support HTTP method conversion, the Spring MVC form tag was updated to suppor
the HTTP method. For example, the following snippet comes from the Pet Clinic
sample:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1636,13 +1536,11 @@ sample:
<p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>
----
====
The preceding example perform an HTTP POST, with the "`real`" DELETE method hidden behind a
request parameter. It is picked up by the `HiddenHttpMethodFilter`, which is defined in
web.xml, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1656,11 +1554,9 @@ web.xml, as the following example shows:
<servlet-name>petclinic</servlet-name>
</filter-mapping>
----
====
The following example shows the corresponding `@Controller` method:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1670,7 +1566,6 @@ The following example shows the corresponding `@Controller` method:
return "redirect:/owners/" + ownerId;
}
----
====
[[mvc-view-jsp-formtaglib-html5]]
@@ -1715,7 +1610,6 @@ To be able to use Tiles, you have to configure it by using files that contain de
http://tiles.apache.org[]). In Spring, this is done by using the `TilesConfigurer`.
The following example `ApplicationContext` configuration shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1731,7 +1625,6 @@ The following example `ApplicationContext` configuration shows how to do so:
</property>
</bean>
----
====
The preceding example defines five files that contain definitions. The files are all located in
the `WEB-INF/defs` directory. At initialization of the `WebApplicationContext`, the
@@ -1744,7 +1637,6 @@ implementations, the `UrlBasedViewResolver` and the `ResourceBundleViewResolver`
You can specify locale-specific Tiles definitions by adding an underscore and then
the locale, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1757,7 +1649,6 @@ the locale, as the following example shows:
</property>
</bean>
----
====
With the preceding configuration, `tiles_fr_FR.xml` is used for requests with the `fr_FR` locale,
and `tiles.xml` is used by default.
@@ -1773,7 +1664,6 @@ them otherwise in the file names for Tiles definitions.
The `UrlBasedViewResolver` instantiates the given `viewClass` for each view it has to
resolve. The following bean defines a `UrlBasedViewResolver`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1781,7 +1671,6 @@ resolve. The following bean defines a `UrlBasedViewResolver`:
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
</bean>
----
====
[[mvc-view-tiles-resource]]
@@ -1792,7 +1681,6 @@ view names and view classes that the resolver can use. The following example sho
definition for a `ResourceBundleViewResolver` and the corresponding view names and view
classes (taken from the Pet Clinic sample):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1815,7 +1703,6 @@ classes (taken from the Pet Clinic sample):
findOwnersForm.url=/WEB-INF/jsp/findOwners.jsp
...
----
====
When you use the `ResourceBundleViewResolver`, you can easily mix
different view technologies.
@@ -1845,7 +1732,6 @@ configuration, scoped beans, and so on. Note that you need to define one Spring
for each preparer name (as used in your Tiles definitions). The following example shows
how to define a set a `SpringBeanPreparerFactory` property on a `TilesConfigurer` bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -1866,7 +1752,6 @@ how to define a set a `SpringBeanPreparerFactory` property on a `TilesConfigurer
</bean>
----
====
@@ -1883,7 +1768,6 @@ package `org.springframework.web.servlet.view.feed`.
optionally override the `buildFeedMetadata()` method (the default implementation is
empty). The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1903,11 +1787,9 @@ empty). The following example shows how to do so:
}
----
====
Similar requirements apply for implementing `AbstractRssFeedView`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1926,7 +1808,6 @@ Similar requirements apply for implementing `AbstractRssFeedView`, as the follow
}
}
----
====
The `buildFeedItems()` and `buildFeedEntries()` methods pass in the HTTP request, in case
you need to access the Locale. The HTTP response is passed in only for the setting of
@@ -1973,7 +1854,6 @@ A simple PDF view for a word list could extend
`org.springframework.web.servlet.view.document.AbstractPdfView` and implement the
`buildPdfDocument()` method, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1989,7 +1869,6 @@ A simple PDF view for a word list could extend
}
}
----
====
A controller can return such a view either from an external view definition
(referencing it by name) or as a `View` instance from the handler method.
@@ -2094,7 +1973,6 @@ Configuration is standard for a simple Spring web application: The MVC configura
has to define an `XsltViewResolver` bean and regular MVC annotation configuration.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2112,7 +1990,6 @@ public class WebConfig implements WebMvcConfigurer {
}
}
----
====
@@ -2124,7 +2001,6 @@ We also need a Controller that encapsulates our word-generation logic.
The controller logic is encapsulated in a `@Controller` class, with the
handler method being defined as follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2149,7 +2025,6 @@ handler method being defined as follows:
}
}
----
====
So far, we have only created a DOM document and added it to the Model map. Note that you
can also load an XML file as a `Resource` and use it instead of a custom DOM document.
@@ -2172,7 +2047,6 @@ and end with an `xslt` file extension.
The following example shows an XSLT transform:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@@ -2199,11 +2073,9 @@ The following example shows an XSLT transform:
</xsl:stylesheet>
----
====
The preceding transform is rendered as the following HTML:
====
[source,html,indent=0]
[subs="verbatim,quotes"]
----
@@ -2222,4 +2094,3 @@ The preceding transform is rendered as the following HTML:
</body>
</html>
----
====

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,6 @@ A WebSocket interaction begins with an HTTP request that uses the HTTP `Upgrade`
to upgrade or, in this case, to switch to the WebSocket protocol. The following example
shows such an interaction:
====
[source,yaml,indent=0]
[subs="verbatim,quotes"]
----
@@ -25,12 +24,11 @@ shows such an interaction:
----
<1> The `Upgrade` header.
<2> Using the `Upgrade` connection.
====
Instead of the usual 200 status code, a server with WebSocket support returns output
similar to the following:
====
[source,yaml,indent=0]
[subs="verbatim,quotes"]
----
@@ -41,7 +39,7 @@ similar to the following:
Sec-WebSocket-Protocol: v10.stomp
----
<1> Protocol switch
====
After a successful handshake, the TCP socket underlying the HTTP upgrade request remains
open for both the client and the server to continue to send and receive messages.

View File

@@ -29,7 +29,6 @@ Creating a WebSocket server is as simple as implementing `WebSocketHandler` or,
likely, extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`. The following
example uses `TextWebSocketHandler`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -46,12 +45,10 @@ example uses `TextWebSocketHandler`:
}
----
====
There is dedicated WebSocket Java configuration and XML namespace support for mapping the preceding
WebSocket handler to a specific URL, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -75,11 +72,9 @@ WebSocket handler to a specific URL, as the following example shows:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -100,7 +95,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The preceding example is for use in Spring MVC applications and should be included in the
configuration of a <<mvc-servlet,`DispatcherServlet`>>. However, Spring's WebSocket
@@ -126,7 +120,6 @@ You can use such an interceptor to preclude the handshake or to make any attribu
available to the `WebSocketSession`. The following example uses a built-in interceptor
to pass HTTP session attributes to the WebSocket session:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -142,11 +135,9 @@ to pass HTTP session attributes to the WebSocket session:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -170,7 +161,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
A more advanced option is to extend the `DefaultHandshakeHandler` that performs
the steps of the WebSocket handshake, including validating the client origin,
@@ -228,7 +218,6 @@ upgrade to a Servlet container version with JSR-356 support, it should
be possible to selectively enable or disable web fragments (and SCI scanning)
through the use of the `<absolute-ordering />` element in `web.xml`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -243,13 +232,11 @@ through the use of the `<absolute-ordering />` element in `web.xml`, as the foll
</web-app>
----
====
You can then selectively enable web fragments by name, such as Spring's own
`SpringServletContainerInitializer` that provides support for the Servlet 3
Java initialization API. The following example shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -266,7 +253,6 @@ Java initialization API. The following example shows how to do so:
</web-app>
----
====
@@ -281,7 +267,6 @@ and others.
For Tomcat, WildFly, and GlassFish, you can add a `ServletServerContainerFactoryBean` to your
WebSocket Java config, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -299,11 +284,9 @@ WebSocket Java config, as the following example shows:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -323,7 +306,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
NOTE: For client-side WebSocket configuration, you should use `WebSocketContainerFactoryBean`
(XML) or `ContainerProvider.getWebSocketContainer()` (Java configuration).
@@ -332,7 +314,6 @@ For Jetty, you need to supply a pre-configured Jetty `WebSocketServerFactory` an
that into Spring's `DefaultHandshakeHandler` through your WebSocket Java config.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -359,11 +340,9 @@ The following example shows how to do so:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -401,7 +380,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
@@ -430,7 +408,6 @@ The three possible behaviors are:
You can configure WebSocket and SockJS allowed origins, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -454,11 +431,9 @@ You can configure WebSocket and SockJS allowed origins, as the following example
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -479,7 +454,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
@@ -532,7 +506,6 @@ polling is used.
All transport requests have the following URL structure:
====
----
http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
----
@@ -542,7 +515,6 @@ where:
* `{server-id}` is useful for routing requests in a cluster but is not used otherwise.
* `{session-id}` correlates HTTP requests belonging to a SockJS session.
* `{transport}` indicates the transport type (for example, `websocket`, `xhr-streaming`, and others).
====
The WebSocket transport needs only a single HTTP request to do the WebSocket handshake.
All messages thereafter are exchanged on that socket.
@@ -572,7 +544,6 @@ http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated test
You can enable SockJS through Java configuration, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -592,11 +563,9 @@ You can enable SockJS through Java configuration, as the following example shows
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -618,7 +587,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The preceding example is for use in Spring MVC applications and should be included in the
configuration of a <<mvc-servlet,`DispatcherServlet`>>. However, Spring's WebSocket
@@ -690,7 +658,6 @@ a URL from the same origin as the application.
The following example shows how to do so in Java configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -708,7 +675,6 @@ The following example shows how to do so in Java configuration:
}
----
====
The XML namespace provides a similar option through the `<websocket:sockjs>` element.
@@ -821,7 +787,6 @@ to the server. At present there are two implementations:
The following example shows how to create a SockJS client and connect to a SockJS endpoint:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -832,7 +797,6 @@ The following example shows how to create a SockJS client and connect to a SockJ
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.doHandshake(new MyWebSocketHandler(), "ws://example.com:8080/sockjs");
----
====
NOTE: SockJS uses JSON formatted arrays for messages. By default, Jackson 2 is used and needs
to be on the classpath. Alternatively, you can configure a custom implementation of
@@ -842,7 +806,6 @@ To use `SockJsClient` to simulate a large number of concurrent users, you
need to configure the underlying HTTP client (for XHR transports) to allow a sufficient
number of connections and threads. The following example shows how to do so with Jetty:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -850,12 +813,10 @@ HttpClient jettyHttpClient = new HttpClient();
jettyHttpClient.setMaxConnectionsPerDestination(1000);
jettyHttpClient.setExecutor(new QueuedThreadPool(1000));
----
====
The following example shows the server-side SockJS-related properties (see javadoc for details)
that you should also consider customizing:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -877,7 +838,6 @@ that you should also consider customizing:
<2> Set the `httpMessageCacheSize` property to 1,000 (the default is `100`).
<3> Set the `disconnectDelay` property to 30 property seconds (the default is five seconds
-- `5 * 1000`).
====
@@ -908,7 +868,6 @@ either text or binary.
STOMP is a frame-based protocol whose frames are modeled on HTTP. The following listing shows the structure
of a STOMP frame:
====
----
COMMAND
header1:value1
@@ -916,7 +875,6 @@ header2:value2
Body^@
----
====
Clients can use the `SEND` or `SUBSCRIBE` commands to send or subscribe for
messages, along with a `destination` header that describes what the
@@ -940,7 +898,6 @@ The following example shows a client subscribing to receive stock quotes, which
the server may emit periodically (for example, via a scheduled task that sends messages
through a `SimpMessagingTemplate` to the broker):
====
----
SUBSCRIBE
id:sub-1
@@ -948,12 +905,10 @@ destination:/topic/price.stock.*
^@
----
====
The following example shows a client that sends a trade request, which the server
can handle through an `@MessageMapping` method:
====
----
SEND
destination:/queue/trade
@@ -962,7 +917,6 @@ content-length:44
{"action":"BUY","ticker":"MMM","shares",44}^@
----
====
After the execution, the server can
broadcast a trade confirmation message and details down to the client.
@@ -977,7 +931,6 @@ exchanges.
STOMP servers can use the `MESSAGE` command to broadcast messages to all subscribers.
The following example shows a server sending a stock quote to a subscribed client:
====
----
MESSAGE
message-id:nxahklf6-1
@@ -986,7 +939,6 @@ destination:/topic/price.stock.MMM
{"ticker":"MMM","price":129.45}^@
----
====
A server cannot send unsolicited messages. All messages
from a server must be in response to a specific client subscription, and the
@@ -1026,7 +978,6 @@ STOMP over WebSocket support is available in the `spring-messaging` and
`spring-websocket` modules. Once you have those dependencies, you can expose a STOMP
endpoints, over WebSocket with <<websocket-fallback>>, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1056,11 +1007,10 @@ client needs to connect for the WebSocket handshake.
`@MessageMapping` methods in `@Controller` classes.
<3> Use the built-in message broker for subscriptions and broadcasting and
route messages whose destination header begins with `/topic `or `/queue` to the broker.
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -1082,7 +1032,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
NOTE: For the built-in simple broker, the `/topic` and `/queue` prefixes do not have any special
meaning. They are merely a convention to differentiate between pub-sub versus point-to-point
@@ -1099,7 +1048,6 @@ https://github.com/JSteunou/webstomp-client[JSteunou/webstomp-client] is the mos
actively maintained and evolving successor of that library. The following example code
is based on it:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@@ -1109,11 +1057,9 @@ is based on it:
stompClient.connect({}, function(frame) {
}
----
====
Alternatively, if you connect through WebSocket (without SockJS), you can use the following code:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@@ -1123,7 +1069,6 @@ Alternatively, if you connect through WebSocket (without SockJS), you can use th
stompClient.connect({}, function(frame) {
}
----
====
Note that `stompClient` in the preceding example does not need to specify `login` and `passcode` headers.
Even if it did, they would be ignored (or, rather, overridden) on the server side. See
@@ -1146,7 +1091,6 @@ To configure the underlying WebSocket server, the information in
<<websocket-server-runtime-configuration>> applies. For Jetty, however you need to set
the `HandshakeHandler` and `WebSocketPolicy` through the `StompEndpointRegistry`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1171,7 +1115,6 @@ the `HandshakeHandler` and `WebSocketPolicy` through the `StompEndpointRegistry`
}
}
----
====
@@ -1237,7 +1180,6 @@ to broadcast to subscribed clients.
We can trace the flow through a simple example. Consider the following example, which sets up a server:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1269,7 +1211,6 @@ We can trace the flow through a simple example. Consider the following example,
}
----
====
The preceding example supports the following flow:
@@ -1419,7 +1360,6 @@ when a subscription is stored and ready for broadcasts, a client should ask for
receipt if the server supports it (simple broker does not). For example, with the Java
<<websocket-stomp-client, STOMP client>>, you could do the following to add a receipt:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1438,7 +1378,6 @@ receipt if the server supports it (simple broker does not). For example, with th
// Subscription ready...
});
----
====
A server side option is <<websocket-stomp-interceptors,to register>> an
`ExecutorChannelInterceptor` on the `brokerChannel` and implement the `afterMessageHandled`
@@ -1453,7 +1392,6 @@ An application can use `@MessageExceptionHandler` methods to handle exceptions f
itself or through a method argument if you want to get access to the exception instance.
The following example declares an exception through a method argument:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1469,7 +1407,6 @@ The following example declares an exception through a method argument:
}
}
----
====
`@MessageExceptionHandler` methods support flexible method signatures and support the same
method argument types and return values as <<websocket-stomp-message-mapping,`@MessageMapping`>> methods.
@@ -1490,7 +1427,6 @@ The easiest way to do so is to inject a `SimpMessagingTemplate` and
use it to send messages. Typically, you would inject it by
type, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1512,7 +1448,6 @@ type, as the following example shows:
}
----
====
However, you can also qualify it by its name (`brokerMessagingTemplate`), if another
bean of the same type exists.
@@ -1535,7 +1470,6 @@ https://stomp.github.io/stomp-specification-1.2.html#Heart-beating[STOMP heartbe
For that, you can declare your own scheduler or use the one that is automatically
declared and used internally. The following example shows how to declare your own scheduler:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1561,7 +1495,6 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
}
}
----
====
@@ -1582,7 +1515,6 @@ and run it with STOMP support enabled. Then you can enable the STOMP broker rela
The following example configuration enables a full-featured broker:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1603,11 +1535,9 @@ The following example configuration enables a full-featured broker:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -1629,7 +1559,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The STOMP broker relay in the preceding configuration is a Spring
{api-spring-framework}/messaging/MessageHandler.html[`MessageHandler`]
@@ -1688,7 +1617,6 @@ connectivity is lost, to the same host and port. If you wish to supply multiple
on each attempt to connect, you can configure a supplier of addresses, instead of a
fixed host and port. The following example shows how to do that:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1711,7 +1639,6 @@ public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
}
}
----
====
You can also configure the STOMP broker relay with a `virtualHost` property.
The value of this property is set as the `host` header of every `CONNECT` frame
@@ -1731,7 +1658,6 @@ you are more used to messaging conventions, you can switch to using dot (`.`) as
The following example shows how to do so in Java configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1749,11 +1675,9 @@ The following example shows how to do so in Java configuration:
}
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -1779,12 +1703,10 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
After that, a controller can use a dot (`.`) as the separator in `@MessageMapping` methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1798,7 +1720,6 @@ as the following example shows:
}
}
----
====
The client can now send a message to `/app/red.blue.green123`.
@@ -1896,7 +1817,6 @@ the user header on the CONNECT `Message`. Spring notes and saves the authenticat
user and associate it with subsequent STOMP messages on the same session. The following
example shows how register a custom authentication interceptor:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1921,7 +1841,6 @@ example shows how register a custom authentication interceptor:
}
}
----
====
Also, note that, when you use Spring Security's authorization for messages, at present,
you need to ensure that the authentication `ChannelInterceptor` config is ordered
@@ -1956,7 +1875,6 @@ A message-handling method can send messages to the user associated with
the message being handled through the `@SendToUser` annotation (also supported on
the class-level to share a common destination), as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1971,14 +1889,12 @@ the class-level to share a common destination), as the following example shows:
}
}
----
====
If the user has more than one session, by default, all of the sessions subscribed
to the given destination are targeted. However, sometimes, it may be necessary to
target only the session that sent the message being handled. You can do so by
setting the `broadcast` attribute to false, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -1998,7 +1914,6 @@ setting the `broadcast` attribute to false, as the following example shows:
}
}
----
====
NOTE: While user destinations generally imply an authenticated user, it is not strictly required.
A WebSocket session that is not associated with an authenticated user
@@ -2011,7 +1926,6 @@ component by, for example, injecting the `SimpMessagingTemplate` created by the
the XML namespace. (The bean name is `"brokerMessagingTemplate"` if required
for qualification with `@Qualifier`.) The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2033,7 +1947,6 @@ public class TradeServiceImpl implements TradeService {
}
}
----
====
NOTE: When you use user destinations with an external message broker, you should check the broker
documentation on how to manage inactive queues, so that, when the user session is
@@ -2063,7 +1976,6 @@ not match the exact order of publication.
If this is an issue, enable the `setPreservePublishOrder` flag, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2079,11 +1991,9 @@ If this is an issue, enable the `setPreservePublishOrder` flag, as the following
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -2102,7 +2012,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
When the flag is set, messages within the same client session are published to the
`clientOutboundChannel` one at a time, so that the order of publication is guaranteed.
@@ -2158,7 +2067,6 @@ of a STOMP connection but not for every client message. Applications can also re
`ChannelInterceptor` to intercept any message and in any part of the processing chain.
The following example shows how to intercept inbound messages from clients:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2172,12 +2080,10 @@ The following example shows how to intercept inbound messages from clients:
}
}
----
====
A custom `ChannelInterceptor` can use `StompHeaderAccessor` or `SimpMessageHeaderAccessor`
to access information about the message, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2192,7 +2098,6 @@ to access information about the message, as the following example shows:
}
}
----
====
Applications can also implement `ExecutorChannelInterceptor`, which is a sub-interface
of `ChannelInterceptor` with callbacks in the thread in which the messages are handled.
@@ -2215,7 +2120,6 @@ Spring provides a STOMP over WebSocket client and a STOMP over TCP client.
To begin, you can create and configure `WebSocketStompClient`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2224,7 +2128,6 @@ To begin, you can create and configure `WebSocketStompClient`, as the following
stompClient.setMessageConverter(new StringMessageConverter());
stompClient.setTaskScheduler(taskScheduler); // for heartbeats
----
====
In the preceding example, you could replace `StandardWebSocketClient` with `SockJsClient`,
since that is also an implementation of `WebSocketClient`. The `SockJsClient` can
@@ -2233,7 +2136,6 @@ use WebSocket or HTTP-based transport as a fallback. For more details, see
Next, you can establish a connection and provide a handler for the STOMP session, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2241,11 +2143,9 @@ Next, you can establish a connection and provide a handler for the STOMP session
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect(url, sessionHandler);
----
====
When the session is ready for use, the handler is notified, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2257,25 +2157,21 @@ public class MyStompSessionHandler extends StompSessionHandlerAdapter {
}
}
----
====
Once the session is established, any payload can be sent and is
serialized with the configured `MessageConverter`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
session.send("/topic/something", "payload");
----
====
You can also subscribe to destinations. The `subscribe` methods require a handler
for messages on the subscription and returns a `Subscription` handle that you can
use to unsubscribe. For each received message, the handler can specify the target
`Object` type to which the payload should be deserialized, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2293,7 +2189,6 @@ session.subscribe("/topic/something", new StompFrameHandler() {
});
----
====
To enable STOMP heartbeat, you can configure `WebSocketStompClient` with a `TaskScheduler`
and optionally customize the heartbeat intervals (10 seconds for write inactivity,
@@ -2329,7 +2224,6 @@ transport-level errors including `ConnectionLostException`.
Each WebSocket session has a map of attributes. The map is attached as a header to
inbound client messages and may be accessed from a controller method, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2343,7 +2237,6 @@ public class MyController {
}
}
----
====
You can declare a Spring-managed bean in the `websocket` scope.
You can inject WebSocket-scoped beans into controllers and any channel interceptors
@@ -2351,7 +2244,6 @@ registered on the `clientInboundChannel`. Those are typically singletons and liv
longer than any individual WebSocket session. Therefore, you need to use a
scope proxy mode for WebSocket-scoped beans, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2388,7 +2280,6 @@ scope proxy mode for WebSocket-scoped beans, as the following example shows:
}
}
----
====
As with any custom scope, Spring initializes a new `MyBean` instance the first
time it is accessed from the controller and stores the instance in the WebSocket
@@ -2462,7 +2353,6 @@ documentation of the XML schema for important additional details.
The following example shows a possible configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2479,11 +2369,9 @@ The following example shows a possible configuration:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -2503,7 +2391,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
You can also use the WebSocket transport configuration shown earlier to configure the
maximum allowed size for incoming STOMP messages. In theory, a WebSocket
@@ -2521,7 +2408,6 @@ minimum.
The following example shows one possible configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@@ -2538,11 +2424,9 @@ The following example shows one possible configuration:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@@ -2562,7 +2446,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
An important point about scaling involves using multiple application instances.
Currently, you cannot do that with the simple broker.