diff --git a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc index 9347519dc2..e1a031e33c 100644 --- a/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc +++ b/framework-docs/modules/ROOT/pages/integration/rest-clients.adoc @@ -363,12 +363,13 @@ If necessary the `Content-Type` may also be set explicitly. [[rest-http-interface]] == HTTP Interface -The Spring Framework lets you define an HTTP service as a Java interface with annotated -methods for HTTP exchanges. You can then generate a proxy that implements this interface -and performs the exchanges. This helps to simplify HTTP remote access which often -involves a facade that wraps the details of using the underlying HTTP client. +The Spring Framework lets you define an HTTP service as a Java interface with +`@HttpExchange` methods. You can pass such an interface to `HttpServiceProxyFactory` +to create a proxy which performs requests through an HTTP client such as `RestClient` +or `WebClient`. You can also implement the interface from an `@Controller` for server +request handling. -One, declare an interface with `@HttpExchange` methods: +Start by creating the interface with `@HttpExchange` methods: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -382,30 +383,31 @@ One, declare an interface with `@HttpExchange` methods: } ---- -Two, create a proxy that will perform the declared HTTP exchanges, -either using `WebClient`: +Now you can create a proxy that performs requests when methods are called. + +For `RestClient`: [source,java,indent=0,subs="verbatim,quotes"] ---- - WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build(); - WebClientAdapter adapter = WebClientAdapter.forClient(webClient) + RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build(); + RestClientAdapter adapter = RestClientAdapter.create(restClient); HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build(); RepositoryService service = factory.createClient(RepositoryService.class); ---- -using `RestClient`: +For `WebClient`: [source,java,indent=0,subs="verbatim,quotes"] ---- - RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build(); - RestClientAdapter adapter = RestClientAdapter.create(restClient); + WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build(); + WebClientAdapter adapter = WebClientAdapter.forClient(webClient) HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build(); RepositoryService service = factory.createClient(RepositoryService.class); ---- -or using `RestTemplate`: +For `RestTemplate`: [source,java,indent=0,subs="verbatim,quotes"] ---- diff --git a/framework-docs/modules/ROOT/pages/rsocket.adoc b/framework-docs/modules/ROOT/pages/rsocket.adoc index ade8b42c06..1fca0eb90a 100644 --- a/framework-docs/modules/ROOT/pages/rsocket.adoc +++ b/framework-docs/modules/ROOT/pages/rsocket.adoc @@ -871,7 +871,7 @@ interaction type(s): As an alternative to `@MessageMapping`, you can also handle requests with `@RSocketExchange` methods. Such methods are declared on an xref:rsocket-interface[RSocket Interface] and can be used as a requester via -`RSocketServiceProxyFactory` or as a responder. +`RSocketServiceProxyFactory` or implemented by a responder. For example, to handle requests as a responder: diff --git a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-httpexchange.adoc b/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-httpexchange.adoc deleted file mode 100644 index f6d4fe7a41..0000000000 --- a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-httpexchange.adoc +++ /dev/null @@ -1,215 +0,0 @@ -[[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. - - diff --git a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods.adoc b/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods.adoc index 9a01e6f26f..6930c9dbda 100644 --- a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods.adoc +++ b/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods.adoc @@ -4,7 +4,7 @@ [.small]#xref:web/webmvc/mvc-controller/ann-methods.adoc[See equivalent in the Servlet stack]# -`@RequestMapping` and `@HttpExchange` handler methods have a flexible signature and can choose from a range of +`@RequestMapping` handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values. diff --git a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc b/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc index a2b5f261bf..57203a2720 100644 --- a/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc +++ b/framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc @@ -1,8 +1,15 @@ [[webflux-ann-requestmapping]] -= Request Mapping += Mapping Requests [.small]#xref:web/webmvc/mvc-controller/ann-requestmapping.adoc[See equivalent in the Servlet stack]# +This section discusses request mapping for annotated controllers. + +[[webflux-ann-requestmapping-annotation]] +== `@RequestMapping` + +[.small]#xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-annotation[See equivalent in the Servlet stack]# + The `@RequestMapping` annotation is used to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level @@ -500,3 +507,68 @@ Kotlin:: +[[webflux-ann-httpexchange-annotation]] +== `@HttpExchange` +[.small]#xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-httpexchange-annotation[See equivalent in the Reactive stack]# + +As an alternative to `@RequestMapping`, you can also handle requests with `@HttpExchange` +methods. Such methods are declared on an +xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface] and can be used as +a client via `HttpServiceProxyFactory` or implemented by a server `@Controller`. + +For example: + +[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) { + // ... + } + } +---- +====== + +There some differences between `@HttpExchange` and `@RequestMapping` since the +former needs to remain suitable for client and server use. For example, while +`@RequestMapping` can be declared to handle any number of paths and each path can +be a pattern, `@HttpExchange` must be declared with a single, concrete path. There are +also differences in the supported method parameters. Generally, `@HttpExchange` supports +a subset of method parameters that `@RequestMapping` does, excluding any parameters that +are server side only. For details see the list of supported method parameters for +xref:integration/rest-clients.adoc#rest-http-interface-method-parameters[HTTP interface] and for +xref:web/webflux/controller/ann-methods/arguments.adoc[@RequestMapping]. diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-httpexchange.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-httpexchange.adoc deleted file mode 100644 index 21ef7588bd..0000000000 --- a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-httpexchange.adoc +++ /dev/null @@ -1,215 +0,0 @@ -[[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. - - diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods.adoc index a44b36cc9c..853e26607d 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods.adoc @@ -4,7 +4,7 @@ [.small]#xref:web/webflux/controller/ann-methods.adoc[See equivalent in the Reactive stack]# -`@RequestMapping` and `@HttpExchange` handler methods have a flexible signature and can choose from a range of +`@RequestMapping` handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values. diff --git a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc index 661981354c..bac27294f2 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc @@ -1,8 +1,17 @@ [[mvc-ann-requestmapping]] -= Request Mapping += Mapping Requests [.small]#xref:web/webflux/controller/ann-requestmapping.adoc[See equivalent in the Reactive stack]# +This section discusses request mapping for annotated controllers. + + + +[[mvc-ann-requestmapping-annotation]] +== `@RequestMapping` + +[.small]#xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-requestmapping-annotation[See equivalent in the Reactive stack]# + You can use the `@RequestMapping` annotation to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level @@ -549,3 +558,68 @@ Kotlin:: +[[mvc-ann-httpexchange-annotation]] +== `@HttpExchange` +[.small]#xref:web/webflux/controller/ann-requestmapping.adoc#webflux-ann-httpexchange-annotation[See equivalent in the Reactive stack]# + +As an alternative to `@RequestMapping`, you can also handle requests with `@HttpExchange` +methods. Such methods are declared on an +xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface] and can be used as +a client via `HttpServiceProxyFactory` or implemented by a server `@Controller`. + +For example: + +[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) { + // ... + } + } +---- +====== + +There some differences between `@HttpExchange` and `@RequestMapping` since the +former needs to remain suitable for client and server use. For example, while +`@RequestMapping` can be declared to handle any number of paths and each path can +be a pattern, `@HttpExchange` must be declared with a single, concrete path. There are +also differences in the supported method parameters. Generally, `@HttpExchange` supports +a subset of method parameters that `@RequestMapping` does, excluding any parameters that +are server side only. For details see the list of supported method parameters for +xref:integration/rest-clients.adoc#rest-http-interface-method-parameters[HTTP interface] and for +xref:web/webmvc/mvc-controller/ann-methods/arguments.adoc[@RequestMapping].