Remove admonitions surrounding code snippets
This commit is contained in:
@@ -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());
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
----
|
||||
====
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user