Support @HttpExchange for server-side handling
See gh-30980
This commit is contained in:
committed by
rstoyanchev
parent
646fd3edcc
commit
d1d5b54f12
@@ -0,0 +1,215 @@
|
||||
[[webflux-ann-httpexchange]]
|
||||
= HttpExchange
|
||||
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc[See equivalent in the Servlet stack]#
|
||||
|
||||
Similarly to
|
||||
xref:web/webflux/controller/ann-requestmapping.adoc[`@RequestMapping`],
|
||||
you can use the `@HttpExchange` annotation to map requests to controllers
|
||||
methods. However, while `@RequestMapping` is only supported on the server side, `@HttpExchange` can be used both to create a server-side mapping and
|
||||
xref:integration/rest-clients.adoc#rest-http-interface[an HTTP
|
||||
Interface Client] that allows making requests.
|
||||
|
||||
`@HttpExchange` has various attributes to match by URL, HTTP method, and media
|
||||
types. You can use it at the class level to express shared mappings or at the
|
||||
method level to narrow down to a specific endpoint mapping.
|
||||
|
||||
There are also HTTP method specific shortcut variants of `@HttpExchange`:
|
||||
|
||||
* `@GetExchange`
|
||||
* `@PostExchange`
|
||||
* `@PutExchange`
|
||||
* `@DeleteExchange`
|
||||
* `@PatchExchange`
|
||||
|
||||
// TODO
|
||||
The shortcuts are xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-composed[Custom Annotations] that are provided
|
||||
because, arguably, most controller methods should be mapped to a specific
|
||||
HTTP method versus using `@HttpExchange`, which, by default, matches
|
||||
to all HTTP methods.
|
||||
An `@HttpExchange` is still needed at the class level to express shared mappings.
|
||||
|
||||
The following example has type and method level mappings:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@RestController
|
||||
@HttpExchange("/persons")
|
||||
class PersonController {
|
||||
|
||||
@GetExchange("/{id}")
|
||||
public Person getPerson(@PathVariable Long id) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@PostExchange
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public void add(@RequestBody Person person) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@RestController
|
||||
@HttpExchange("/persons")
|
||||
class PersonController {
|
||||
|
||||
@GetExchange("/{id}")
|
||||
fun getPerson(@PathVariable id: Long): Person {
|
||||
// ...
|
||||
}
|
||||
|
||||
@PostExchange
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
fun add(@RequestBody person: Person) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
`@HttpExhange` supports a very similar method signature to `@MessageMapping`,
|
||||
however, since it needs to be suitable both for requester and responder use,
|
||||
there are slight differences.
|
||||
|
||||
[[webflux-ann-httpexchange-uri-templates]]
|
||||
== URI patterns
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-uri-templates[See equivalent in the Servlet stack]#
|
||||
|
||||
URI patterns resolution support is very similar to the one offered by xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-uri-templates[`@RequestMapping`], with the difference
|
||||
that while `@RequestMapping` accepts a `String` array as its `value` or `path`
|
||||
parameter that is used to specify the URI patterns, only a single `String` can be passed
|
||||
as the `value` of `@HttpExchange`.
|
||||
|
||||
[[webflux-ann-httpexchange-contenttype]]
|
||||
== Consumable Media Types
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-contenttype[See equivalent in the Servlet stack]#
|
||||
|
||||
You can narrow the request mapping based on the `Content-Type` of the request,
|
||||
as the following example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@PostExchange(path = "/pets", contentType = "application/json") // <1>
|
||||
public void addPet(@RequestBody Pet pet) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using a `contentType` attribute to narrow the mapping by the content type.
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@PostExchange("/pets", contentType = "application/json") // <1>
|
||||
fun addPet(@RequestBody pet: Pet) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using a `contentType` attribute to narrow the mapping by the content type.
|
||||
======
|
||||
|
||||
The `contentType` attribute accepts a single `String` as the attribute value.
|
||||
|
||||
You can also declare a shared `contentType` attribute at the class level.
|
||||
Unlike most other request-mapping attributes, however, when used at the
|
||||
class level, a method-level `contentType` attribute overrides rather than
|
||||
extends the class-level declaration.
|
||||
|
||||
TIP: `MediaType` provides constants for commonly used media types, such as
|
||||
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.
|
||||
|
||||
|
||||
[[webflux-ann-httpexchange-accept]]
|
||||
== Producible Media Types
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-accept[See equivalent in the Servlet stack]#
|
||||
|
||||
You can narrow the request mapping based on the `Accept` request header and the list of
|
||||
content types that a controller method produces, as the following example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@GetExchange(path = "/pets/{petId}", accept = "application/json") // <1>
|
||||
@ResponseBody
|
||||
public Pet getPet(@PathVariable String petId) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using an `accept` attribute to narrow the mapping by the content type that
|
||||
can be served.
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@GetExchange("/pets/{petId}", accept = ["application/json"]) // <1>
|
||||
@ResponseBody
|
||||
fun getPet(@PathVariable petId: String): Pet {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using an `accept` attribute to narrow the mapping by the content type that
|
||||
can be served.
|
||||
======
|
||||
|
||||
The `accept` attribute accepts a `String` array as the attribute value.
|
||||
|
||||
You can declare a shared `accept` attribute at the class level. Unlike most
|
||||
other request-mapping attributes, however, when used at the class level,
|
||||
a method-level `accept` attribute
|
||||
overrides rather than extends the class-level declaration.
|
||||
|
||||
TIP: `MediaType` provides constants for commonly used media types, such as
|
||||
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.
|
||||
|
||||
|
||||
[[webflux-ann-httpexchange-params-and-headers]]
|
||||
== Parameters, headers
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-params-and-headers[See equivalent in the Servlet stack]#
|
||||
|
||||
You can narrow request mappings based on request parameter and headers
|
||||
conditions. It is supported for `@HttpExchange` in the same way as in xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-params-and-headers[`@RequestMapping` parameters and headers support].
|
||||
|
||||
|
||||
[[webflux-ann-httpexchange-head-options]]
|
||||
== HTTP HEAD, OPTIONS
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-head-options[See equivalent in the Servlet stack]#
|
||||
|
||||
The support of `HTTP HEAD` and `HTTP OPTIONS` in `@HttpExchange` annotated
|
||||
controllers is the same xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-head-options[
|
||||
as in `@RequestMapping` annotated controllers].
|
||||
|
||||
[[webflux-ann-httpexchange-composed]]
|
||||
== Custom Annotations
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-composed[See equivalent in the Servlet stack]#
|
||||
|
||||
`@HttpExchange` annotated controllers support the use of xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[composed annotations]
|
||||
for request mapping. Those are annotations that are themselves meta-annotated
|
||||
with `@HttpExchange` and composed to redeclare a subset (or all) of the
|
||||
`@HttpExchange` attributes with a narrower, more specific purpose.
|
||||
|
||||
`@GetExchange`, `@PostExchange`, `@PutExchange`, `@DeleteExchange`,
|
||||
and `@PatcExchange` are examples of composed annotations. They are provided
|
||||
because, arguably, most controller methods should be mapped to a specific
|
||||
HTTP method versus using `@HttpExchange`, which, by default,
|
||||
matches to all HTTP methods. If you need an example of composed annotations,
|
||||
look at how those are declared.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
[.small]#xref:web/webmvc/mvc-controller/ann-methods.adoc[See equivalent in the Servlet stack]#
|
||||
|
||||
`@RequestMapping` handler methods have a flexible signature and can choose from a range of
|
||||
`@RequestMapping` and `@HttpExchange` handler methods have a flexible signature and can choose from a range of
|
||||
supported controller method arguments and return values.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
[[mvc-ann-httpexchange]]
|
||||
= HttpExchange
|
||||
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc[
|
||||
See equivalent in the Reactive stack]#
|
||||
|
||||
Similarly to
|
||||
xref:web/webmvc/mvc-controller/ann-requestmapping.adoc[`@RequestMapping`],
|
||||
you can use the `@HttpExchange` annotation to map requests to controllers
|
||||
methods. However, while `@RequestMapping` is only supported on the server side, `@HttpExchange` can be used both to create a server-side mapping and
|
||||
xref:integration/rest-clients.adoc#rest-http-interface[an HTTP
|
||||
Interface Client] that allows making requests.
|
||||
|
||||
`@HttpExchange` has various attributes to match by URL, HTTP method, and media
|
||||
types. You can use it at the class level to express shared mappings or at the
|
||||
method level to narrow down to a specific endpoint mapping.
|
||||
|
||||
There are also HTTP method specific shortcut variants of `@HttpExchange`:
|
||||
|
||||
* `@GetExchange`
|
||||
* `@PostExchange`
|
||||
* `@PutExchange`
|
||||
* `@DeleteExchange`
|
||||
* `@PatchExchange`
|
||||
|
||||
The shortcuts are xref:web/webmvc/mvc-controller/ann-httpexchange.adoc#mvc-ann-httpexchange-composed[Custom Annotations] that are provided
|
||||
because, arguably, most controller methods should be mapped to a specific
|
||||
HTTP method versus using `@HttpExchange`, which, by default, matches
|
||||
to all HTTP methods.
|
||||
An `@HttpExchange` is still needed at the class level to express shared mappings.
|
||||
|
||||
The following example has type and method level mappings:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@RestController
|
||||
@HttpExchange("/persons")
|
||||
class PersonController {
|
||||
|
||||
@GetExchange("/{id}")
|
||||
public Person getPerson(@PathVariable Long id) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@PostExchange
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public void add(@RequestBody Person person) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@RestController
|
||||
@HttpExchange("/persons")
|
||||
class PersonController {
|
||||
|
||||
@GetExchange("/{id}")
|
||||
fun getPerson(@PathVariable id: Long): Person {
|
||||
// ...
|
||||
}
|
||||
|
||||
@PostExchange
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
fun add(@RequestBody person: Person) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
`@HttpExhange` supports a very similar method signature to `@MessageMapping`,
|
||||
however, since it needs to be suitable both for requester and responder use,
|
||||
there are slight differences, which are discussed below.
|
||||
|
||||
[[mvc-ann-httpexchange-uri-templates]]
|
||||
== URI patterns
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-uri-templates[See equivalent in the Reactive stack]#
|
||||
|
||||
URI patterns resolution support is very similar to the one offered by xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-uri-templates[`@RequestMapping`], with the difference
|
||||
that while `@RequestMapping` accepts a `String` array as its `value` or `path`
|
||||
parameter that is used to specify the URI patterns, only a single `String` can be passed
|
||||
as the `value` of `@HttpExchange`.
|
||||
|
||||
[[mvc-ann-httpexchange-contenttype]]
|
||||
== Consumable Media Types
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-contenttype[See equivalent in the Reactive stack]#
|
||||
|
||||
You can narrow the request mapping based on the `Content-Type` of the request,
|
||||
as the following example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@PostExchange(path = "/pets", contentType = "application/json") // <1>
|
||||
public void addPet(@RequestBody Pet pet) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using a `contentType` attribute to narrow the mapping by the content type.
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@PostExchange("/pets", contentType = "application/json") // <1>
|
||||
fun addPet(@RequestBody pet: Pet) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using a `contentType` attribute to narrow the mapping by the content type.
|
||||
======
|
||||
|
||||
The `contentType` attribute accepts a single `String` as the attribute value.
|
||||
|
||||
You can also declare a shared `contentType` attribute at the class level.
|
||||
Unlike most other request-mapping attributes, however, when used at the
|
||||
class level, a method-level `contentType` attribute overrides rather than
|
||||
extends the class-level declaration.
|
||||
|
||||
TIP: `MediaType` provides constants for commonly used media types, such as
|
||||
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.
|
||||
|
||||
|
||||
[[mvc-ann-httpexchange-accept]]
|
||||
== Producible Media Types
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-accept[See equivalent in the Reactive stack]#
|
||||
|
||||
You can narrow the request mapping based on the `Accept` request header and the list of
|
||||
content types that a controller method produces, as the following example shows:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||
----
|
||||
@GetExchange(path = "/pets/{petId}", accept = "application/json") // <1>
|
||||
@ResponseBody
|
||||
public Pet getPet(@PathVariable String petId) {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using an `accept` attribute to narrow the mapping by the content type that
|
||||
can be served.
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||
----
|
||||
@GetExchange("/pets/{petId}", accept = ["application/json"]) // <1>
|
||||
@ResponseBody
|
||||
fun getPet(@PathVariable petId: String): Pet {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
<1> Using an `accept` attribute to narrow the mapping by the content type that
|
||||
can be served.
|
||||
======
|
||||
|
||||
The `accept` attribute accepts a `String` array as the attribute value.
|
||||
|
||||
You can declare a shared `accept` attribute at the class level. Unlike most
|
||||
other request-mapping attributes, however, when used at the class level,
|
||||
a method-level `accept` attribute
|
||||
overrides rather than extends the class-level declaration.
|
||||
|
||||
TIP: `MediaType` provides constants for commonly used media types, such as
|
||||
`APPLICATION_JSON_VALUE` and `APPLICATION_XML_VALUE`.
|
||||
|
||||
|
||||
[[mvc-ann-httpexchange-params-and-headers]]
|
||||
== Parameters, headers
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-params-and-headers[See equivalent in the Reactive stack]#
|
||||
|
||||
You can narrow request mappings based on request parameter and headers
|
||||
conditions. It is supported for `@HttpExchange` in the same way as in xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-params-and-headers[`@RequestMapping` parameter and header support] .
|
||||
|
||||
|
||||
[[mvc-ann-httpexchange-head-options]]
|
||||
== HTTP HEAD, OPTIONS
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-head-options[See equivalent in the Reactive stack]#
|
||||
|
||||
The support of `HTTP HEAD` and `HTTP OPTIONS` in `@HttpExchange` annotated
|
||||
controllers is the same xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-head-options[
|
||||
as in `@RequestMapping` annotated controllers].
|
||||
|
||||
[[mvc-ann-httpexchange-composed]]
|
||||
== Custom Annotations
|
||||
[.small]#xref:web/webflux/controller/ann-httpexchange.adoc#webflux-ann-httpexchange-head-options[See equivalent in the Reactive stack]#
|
||||
|
||||
`@HttpExchange` annotated controllers support the use of xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[composed annotations]
|
||||
for request mapping. Those are annotations that are themselves meta-annotated
|
||||
with `@HttpExchange` and composed to redeclare a subset (or all) of the
|
||||
`@HttpExchange` attributes with a narrower, more specific purpose.
|
||||
|
||||
`@GetExchange`, `@PostExchange`, `@PutExchange`, `@DeleteExchange`,
|
||||
and `@PatcExchange` are examples of composed annotations. They are provided
|
||||
because, arguably, most controller methods should be mapped to a specific
|
||||
HTTP method versus using `@HttpExchange`, which, by default,
|
||||
matches to all HTTP methods. If you need an example of composed annotations,
|
||||
look at how those are declared.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
[.small]#xref:web/webflux/controller/ann-methods.adoc[See equivalent in the Reactive stack]#
|
||||
|
||||
`@RequestMapping` handler methods have a flexible signature and can choose from a range of
|
||||
`@RequestMapping` and `@HttpExchange` handler methods have a flexible signature and can choose from a range of
|
||||
supported controller method arguments and return values.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user