Extract code samples from docs
See gh-6313
This commit is contained in:
@@ -86,6 +86,7 @@ dependencies {
|
||||
implementation("org.slf4j:jul-to-slf4j")
|
||||
implementation("org.springframework:spring-test")
|
||||
implementation("org.springframework:spring-web")
|
||||
implementation("org.springframework:spring-webmvc")
|
||||
implementation("org.springframework:spring-webflux")
|
||||
implementation("org.springframework.data:spring-data-couchbase")
|
||||
implementation("org.springframework.data:spring-data-neo4j")
|
||||
|
||||
@@ -1118,12 +1118,9 @@ Sometimes, classes annotated with `@ConfigurationProperties` might not be suitab
|
||||
In these cases, specify the list of types to process using the `@EnableConfigurationProperties` annotation.
|
||||
This can be done on any `@Configuration` class, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(AcmeProperties.class)
|
||||
public class MyConfiguration {
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/enable/MyConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
To use configuration property scanning, add the `@ConfigurationPropertiesScan` annotation to your application.
|
||||
@@ -1131,12 +1128,9 @@ Typically, it is added to the main application class that is annotated with `@Sp
|
||||
By default, scanning will occur from the package of the class that declares the annotation.
|
||||
If you want to define specific packages to scan, you can do so as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
|
||||
public class MyApplication {
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/enable/MyApplication.java[tag=*]
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
@@ -1170,27 +1164,9 @@ This style of configuration works particularly well with the `SpringApplication`
|
||||
|
||||
To work with `@ConfigurationProperties` beans, you can inject them in the same way as any other bean, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Service
|
||||
public class MyService {
|
||||
|
||||
private final AcmeProperties properties;
|
||||
|
||||
@Autowired
|
||||
public MyService(AcmeProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
//...
|
||||
|
||||
@PostConstruct
|
||||
public void openConnection() {
|
||||
Server server = new Server(this.properties.getRemoteAddress());
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/use/MyService.java[tag=*]
|
||||
----
|
||||
|
||||
TIP: Using `@ConfigurationProperties` also lets you generate metadata files that can be used by IDEs to offer auto-completion for your own keys.
|
||||
@@ -1205,13 +1181,9 @@ Doing so can be particularly useful when you want to bind properties to third-pa
|
||||
|
||||
To configure a bean from the `Environment` properties, add `@ConfigurationProperties` to its bean registration, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties(prefix = "another")
|
||||
@Bean
|
||||
public AnotherComponent anotherComponent() {
|
||||
...
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/ThirdPartyConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
Any JavaBean property defined with the `another` prefix is mapped onto that `AnotherComponent` bean in manner similar to the preceding `AcmeProperties` example.
|
||||
@@ -1225,22 +1197,9 @@ Common examples where this is useful include dash-separated environment properti
|
||||
|
||||
As an example, consider the following `@ConfigurationProperties` class:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties(prefix="acme.my-project.person")
|
||||
public class OwnerProperties {
|
||||
|
||||
private String firstName;
|
||||
|
||||
public String getFirstName() {
|
||||
return this.firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/relaxed/OwnerProperties.java[tag=*]
|
||||
----
|
||||
|
||||
With the preceding code, the following properties names can all be used:
|
||||
@@ -1357,18 +1316,9 @@ When lists are configured in more than one place, overriding works by replacing
|
||||
For example, assume a `MyPojo` object with `name` and `description` attributes that are `null` by default.
|
||||
The following example exposes a list of `MyPojo` objects from `AcmeProperties`:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties("acme")
|
||||
public class AcmeProperties {
|
||||
|
||||
private final List<MyPojo> list = new ArrayList<>();
|
||||
|
||||
public List<MyPojo> getList() {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/merge/list/AcmeProperties.java[tag=*]
|
||||
----
|
||||
|
||||
Consider the following configuration:
|
||||
@@ -1421,18 +1371,9 @@ For `Map` properties, you can bind with property values drawn from multiple sour
|
||||
However, for the same property in multiple sources, the one with the highest priority is used.
|
||||
The following example exposes a `Map<String, MyPojo>` from `AcmeProperties`:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties("acme")
|
||||
public class AcmeProperties {
|
||||
|
||||
private final Map<String, MyPojo> map = new HashMap<>();
|
||||
|
||||
public Map<String, MyPojo> getMap() {
|
||||
return this.map;
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/merge/map/AcmeProperties.java[tag=*]
|
||||
----
|
||||
|
||||
Consider the following configuration:
|
||||
@@ -1588,18 +1529,9 @@ Spring Boot attempts to validate `@ConfigurationProperties` classes whenever the
|
||||
You can use JSR-303 `javax.validation` constraint annotations directly on your configuration class.
|
||||
To do so, ensure that a compliant JSR-303 implementation is on your classpath and then add constraint annotations to your fields, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties(prefix="acme")
|
||||
@Validated
|
||||
public class AcmeProperties {
|
||||
|
||||
@NotNull
|
||||
private InetAddress remoteAddress;
|
||||
|
||||
// ... getters and setters
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/validate/AcmeProperties.java[tag=*]
|
||||
----
|
||||
|
||||
TIP: You can also trigger validation by annotating the `@Bean` method that creates the configuration properties with `@Validated`.
|
||||
@@ -1607,30 +1539,9 @@ TIP: You can also trigger validation by annotating the `@Bean` method that creat
|
||||
To ensure that validation is always triggered for nested properties, even when no properties are found, the associated field must be annotated with `@Valid`.
|
||||
The following example builds on the preceding `AcmeProperties` example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@ConfigurationProperties(prefix="acme")
|
||||
@Validated
|
||||
public class AcmeProperties {
|
||||
|
||||
@NotNull
|
||||
private InetAddress remoteAddress;
|
||||
|
||||
@Valid
|
||||
private final Security security = new Security();
|
||||
|
||||
// ... getters and setters
|
||||
|
||||
public static class Security {
|
||||
|
||||
@NotEmpty
|
||||
public String username;
|
||||
|
||||
// ... getters and setters
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/externalizedconfiguration/validate/nested/AcmeProperties.java[tag=*]
|
||||
----
|
||||
|
||||
You can also add a custom Spring `Validator` by creating a bean definition called `configurationPropertiesValidator`.
|
||||
@@ -1685,15 +1596,9 @@ If the value of a property from an application property file is a `SpEL` express
|
||||
Spring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments.
|
||||
Any `@Component`, `@Configuration` or `@ConfigurationProperties` can be marked with `@Profile` to limit when it is loaded, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Profile("production")
|
||||
public class ProductionConfiguration {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/profiles/ProductionConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
NOTE: If `@ConfigurationProperties` beans are registered via `@EnableConfigurationProperties` instead of automatic scanning, the `@Profile` annotation needs to be specified on the `@Configuration` class that has the `@EnableConfigurationProperties` annotation.
|
||||
@@ -2326,28 +2231,9 @@ Methods in your controller are mapped to HTTP by using `@RequestMapping` annotat
|
||||
|
||||
The following code shows a typical `@RestController` that serves JSON data:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@RestController
|
||||
@RequestMapping(value="/users")
|
||||
public class MyRestController {
|
||||
|
||||
@RequestMapping(value="/{user}", method=RequestMethod.GET)
|
||||
public User getUser(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
|
||||
List<Customer> getUserCustomers(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
|
||||
public User deleteUser(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/MyRestController.java[tag=*]
|
||||
----
|
||||
|
||||
Spring MVC is part of the core Spring Framework, and detailed information is available in the {spring-framework-docs}/web.html#mvc[reference documentation].
|
||||
@@ -2395,23 +2281,9 @@ By default, strings are encoded in `UTF-8`.
|
||||
|
||||
If you need to add or customize converters, you can use Spring Boot's `HttpMessageConverters` class, as shown in the following listing:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.http.converter.*;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = ...
|
||||
HttpMessageConverter<?> another = ...
|
||||
return new HttpMessageConverters(additional, another);
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/HttpMessageConvertersConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
Any `HttpMessageConverter` bean that is present in the context is added to the list of converters.
|
||||
@@ -2427,25 +2299,9 @@ Custom serializers are usually https://github.com/FasterXML/jackson-docs/wiki/Ja
|
||||
You can use the `@JsonComponent` annotation directly on `JsonSerializer`, `JsonDeserializer` or `KeyDeserializer` implementations.
|
||||
You can also use it on classes that contain serializers/deserializers as inner classes, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import java.io.*;
|
||||
import com.fasterxml.jackson.core.*;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import org.springframework.boot.jackson.*;
|
||||
|
||||
@JsonComponent
|
||||
public class Example {
|
||||
|
||||
public static class Serializer extends JsonSerializer<SomeObject> {
|
||||
// ...
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<SomeObject> {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/json/MyJsonComponent.java[tag=*]
|
||||
----
|
||||
|
||||
All `@JsonComponent` beans in the `ApplicationContext` are automatically registered with Jackson.
|
||||
@@ -2454,6 +2310,13 @@ Because `@JsonComponent` is meta-annotated with `@Component`, the usual componen
|
||||
Spring Boot also provides {spring-boot-module-code}/jackson/JsonObjectSerializer.java[`JsonObjectSerializer`] and {spring-boot-module-code}/jackson/JsonObjectDeserializer.java[`JsonObjectDeserializer`] base classes that provide useful alternatives to the standard Jackson versions when serializing objects.
|
||||
See {spring-boot-module-api}/jackson/JsonObjectSerializer.html[`JsonObjectSerializer`] and {spring-boot-module-api}/jackson/JsonObjectDeserializer.html[`JsonObjectDeserializer`] in the Javadoc for details.
|
||||
|
||||
The example above can be rewritten to use `JsonObjectSerializer`/`JsonObjectDeserializer` as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{include-springbootfeatures}/webapplications/json/object/MyJsonComponent.java[tag=*]
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[boot-features-spring-message-codes]]
|
||||
@@ -2692,27 +2555,9 @@ To do so, extend `BasicErrorController`, add a public method with a `@RequestMap
|
||||
|
||||
You can also define a class annotated with `@ControllerAdvice` to customize the JSON document to return for a particular controller and/or exception type, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@ControllerAdvice(basePackageClasses = AcmeController.class)
|
||||
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ExceptionHandler(YourException.class)
|
||||
@ResponseBody
|
||||
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
|
||||
HttpStatus status = getStatus(request);
|
||||
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
||||
if (statusCode == null) {
|
||||
return HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
return HttpStatus.valueOf(statusCode);
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/MyControllerAdvice.java[tag=*]
|
||||
----
|
||||
|
||||
In the preceding example, if `YourException` is thrown by a controller defined in the same package as `AcmeController`, a JSON representation of the `CustomErrorType` POJO is used instead of the `ErrorAttributes` representation.
|
||||
@@ -2757,21 +2602,11 @@ To map all `5xx` errors by using a FreeMarker template, your directory structure
|
||||
|
||||
For more complex mappings, you can also add beans that implement the `ErrorViewResolver` interface, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
public class MyErrorViewResolver implements ErrorViewResolver {
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveErrorView(HttpServletRequest request,
|
||||
HttpStatus status, Map<String, Object> model) {
|
||||
// Use the request or status to optionally return a ModelAndView
|
||||
return ...
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/MyErrorViewResolver.java[tag=*]
|
||||
----
|
||||
|
||||
|
||||
You can also use regular Spring MVC features such as {spring-framework-docs}/web.html#mvc-exceptionhandlers[`@ExceptionHandler` methods] and {spring-framework-docs}/web.html#mvc-ann-controller-advice[`@ControllerAdvice`].
|
||||
The `ErrorController` then picks up any unhandled exceptions.
|
||||
|
||||
@@ -2782,37 +2617,16 @@ The `ErrorController` then picks up any unhandled exceptions.
|
||||
For applications that do not use Spring MVC, you can use the `ErrorPageRegistrar` interface to directly register `ErrorPages`.
|
||||
This abstraction works directly with the underlying embedded servlet container and works even if you do not have a Spring MVC `DispatcherServlet`.
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public ErrorPageRegistrar errorPageRegistrar(){
|
||||
return new MyErrorPageRegistrar();
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerErrorPages(ErrorPageRegistry registry) {
|
||||
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/ErrorPageConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
NOTE: If you register an `ErrorPage` with a path that ends up being handled by a `Filter` (as is common with some non-Spring web frameworks, like Jersey and Wicket), then the `Filter` has to be explicitly registered as an `ERROR` dispatcher, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
@Bean
|
||||
public FilterRegistrationBean myFilter() {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||
registration.setFilter(new MyFilter());
|
||||
...
|
||||
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
|
||||
return registration;
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/ServletFilterConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
Note that the default `FilterRegistrationBean` does not include the `ERROR` dispatcher type.
|
||||
@@ -2854,21 +2668,9 @@ As of version 4.2, Spring MVC {spring-framework-docs}/web.html#mvc-cors[supports
|
||||
Using {spring-framework-docs}/web.html#mvc-cors-controller[controller method CORS configuration] with {spring-framework-api}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`] annotations in your Spring Boot application does not require any specific configuration.
|
||||
{spring-framework-docs}/web.html#mvc-cors-global[Global CORS configuration] can be defined by registering a `WebMvcConfigurer` bean with a customized `addCorsMappings(CorsRegistry)` method, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/api/**");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/servlet/CorsConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
|
||||
@@ -2881,61 +2683,21 @@ Unlike Spring MVC, it does not require the Servlet API, is fully asynchronous an
|
||||
Spring WebFlux comes in two flavors: functional and annotation-based.
|
||||
The annotation-based one is quite close to the Spring MVC model, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class MyRestController {
|
||||
|
||||
@GetMapping("/{user}")
|
||||
public Mono<User> getUser(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@GetMapping("/{user}/customers")
|
||||
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
@DeleteMapping("/{user}")
|
||||
public Mono<User> deleteUser(@PathVariable Long user) {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/webflux/MyRestController.java[tag=*]
|
||||
----
|
||||
|
||||
"`WebFlux.fn`", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{include-springbootfeatures}/webapplications/webflux/fn/RoutingConfiguration.java[tag=*]
|
||||
----
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RoutingConfiguration {
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
|
||||
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
|
||||
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
|
||||
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
public class UserHandler {
|
||||
|
||||
public Mono<ServerResponse> getUser(ServerRequest request) {
|
||||
// ...
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
|
||||
// ...
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> deleteUser(ServerRequest request) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
[source,java,indent=0]
|
||||
----
|
||||
include::{include-springbootfeatures}/webapplications/webflux/fn/UserHandler.java[tag=*]
|
||||
----
|
||||
|
||||
WebFlux is part of the Spring Framework and detailed information is available in its {spring-framework-docs}/web-reactive.html#webflux-fn[reference documentation].
|
||||
@@ -2977,21 +2739,9 @@ For example, `+spring.jackson.*+` configuration keys are applied to the Jackson
|
||||
|
||||
If you need to add or customize codecs, you can create a custom `CodecCustomizer` component, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0]
|
||||
[source,java,indent=0]
|
||||
----
|
||||
import org.springframework.boot.web.codec.CodecCustomizer;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
public CodecCustomizer myCodecCustomizer() {
|
||||
return codecConfigurer -> {
|
||||
// ...
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/webflux/CodecConfiguration.java[tag=*]
|
||||
----
|
||||
|
||||
You can also leverage <<boot-features-json-components,Boot's custom JSON serializers and deserializers>>.
|
||||
@@ -3062,21 +2812,9 @@ For that, you can add a bean of type `ErrorAttributes`.
|
||||
To change the error handling behavior, you can implement `ErrorWebExceptionHandler` and register a bean definition of that type.
|
||||
Because a `WebExceptionHandler` is quite low-level, Spring Boot also provides a convenient `AbstractErrorWebExceptionHandler` to let you handle errors in a WebFlux functional way, as shown in the following example:
|
||||
|
||||
[source,java,pending-extract=true,indent=0,subs="verbatim,quotes,attributes"]
|
||||
[source,java,indent=0,subs="verbatim,quotes,attributes"]
|
||||
----
|
||||
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
|
||||
|
||||
// Define constructor here
|
||||
|
||||
@Override
|
||||
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
|
||||
|
||||
return RouterFunctions
|
||||
.route(aPredicate, aHandler)
|
||||
.andRoute(anotherPredicate, anotherHandler);
|
||||
}
|
||||
|
||||
}
|
||||
include::{include-springbootfeatures}/webapplications/webflux/CustomErrorWebExceptionHandler.java[tag=*]
|
||||
----
|
||||
|
||||
For a more complete picture, you can also subclass `DefaultErrorWebExceptionHandler` directly and override specific methods.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class ThirdPartyConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "another")
|
||||
public AnotherComponent anotherComponent() {
|
||||
return new AnotherComponent();
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class AnotherComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.enable;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
|
||||
public class MyApplication {
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.enable;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(AcmeProperties.class)
|
||||
public class MyConfiguration {
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class AcmeProperties {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.merge.list;
|
||||
|
||||
//tag::code[]
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("acme")
|
||||
public class AcmeProperties {
|
||||
|
||||
private final List<MyPojo> list = new ArrayList<>();
|
||||
|
||||
public List<MyPojo> getList() {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class MyPojo {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.merge.map;
|
||||
|
||||
//tag::code[]
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties("acme")
|
||||
public class AcmeProperties {
|
||||
|
||||
private final Map<String, MyPojo> map = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, MyPojo> getMap() {
|
||||
return this.map;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class MyPojo {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.relaxed;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "acme.my-project.person")
|
||||
public class OwnerProperties {
|
||||
|
||||
private String firstName;
|
||||
|
||||
public String getFirstName() {
|
||||
return this.firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.use;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MyService {
|
||||
|
||||
private final AcmeProperties properties;
|
||||
|
||||
public MyService(AcmeProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void openConnection() {
|
||||
Server server = new Server(this.properties.getRemoteAddress());
|
||||
server.start();
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class AcmeProperties {
|
||||
|
||||
Object getRemoteAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Server {
|
||||
|
||||
Server(Object remoteAddress) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.validate;
|
||||
|
||||
//tag::code[]
|
||||
import java.net.InetAddress;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ConfigurationProperties(prefix = "acme")
|
||||
@Validated
|
||||
public class AcmeProperties {
|
||||
|
||||
@NotNull
|
||||
private InetAddress remoteAddress;
|
||||
|
||||
public InetAddress getRemoteAddress() {
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
public void setRemoteAddress(InetAddress remoteAddress) {
|
||||
this.remoteAddress = remoteAddress;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.externalizedconfiguration.validate.nested;
|
||||
|
||||
//tag::code[]
|
||||
import java.net.InetAddress;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ConfigurationProperties(prefix = "acme")
|
||||
@Validated
|
||||
public class AcmeProperties {
|
||||
|
||||
@NotNull
|
||||
private InetAddress remoteAddress;
|
||||
|
||||
@Valid
|
||||
private final Security security = new Security();
|
||||
|
||||
public InetAddress getRemoteAddress() {
|
||||
return this.remoteAddress;
|
||||
}
|
||||
|
||||
public void setRemoteAddress(InetAddress remoteAddress) {
|
||||
this.remoteAddress = remoteAddress;
|
||||
}
|
||||
|
||||
public Security getSecurity() {
|
||||
return this.security;
|
||||
}
|
||||
|
||||
public static class Security {
|
||||
|
||||
@NotEmpty
|
||||
private String username;
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.profiles;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Profile("production")
|
||||
public class ProductionConfiguration {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications;
|
||||
|
||||
//tag::code[]
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class HttpMessageConvertersConfiguration {
|
||||
|
||||
@Bean
|
||||
public HttpMessageConverters customConverters() {
|
||||
HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
|
||||
HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
|
||||
return new HttpMessageConverters(additional, another);
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class AdditionalHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
|
||||
|
||||
@Override
|
||||
protected boolean supports(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Object t, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class AnotherHttpMessageConverter extends AdditionalHttpMessageConverter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.json;
|
||||
|
||||
//tag::code[]
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.ObjectCodec;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
@JsonComponent
|
||||
public class MyJsonComponent {
|
||||
|
||||
public static class Serializer extends JsonSerializer<MyObject> {
|
||||
|
||||
@Override
|
||||
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
|
||||
jgen.writeStringField("name", value.getName());
|
||||
jgen.writeNumberField("age", value.getAge());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<MyObject> {
|
||||
|
||||
@Override
|
||||
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt)
|
||||
throws IOException, JsonProcessingException {
|
||||
ObjectCodec codec = jsonParser.getCodec();
|
||||
JsonNode tree = codec.readTree(jsonParser);
|
||||
String name = tree.get("name").textValue();
|
||||
int age = tree.get("age").intValue();
|
||||
return new MyObject(name, age);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class MyObject {
|
||||
|
||||
MyObject(String name, int age) {
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
Integer getAge() {
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.json.object;
|
||||
|
||||
//tag::code[]
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.ObjectCodec;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.boot.jackson.JsonObjectDeserializer;
|
||||
import org.springframework.boot.jackson.JsonObjectSerializer;
|
||||
|
||||
@JsonComponent
|
||||
public class MyJsonComponent {
|
||||
|
||||
public static class Serializer extends JsonObjectSerializer<MyObject> {
|
||||
|
||||
@Override
|
||||
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
jgen.writeStringField("name", value.getName());
|
||||
jgen.writeNumberField("age", value.getAge());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonObjectDeserializer<MyObject> {
|
||||
|
||||
@Override
|
||||
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
|
||||
JsonNode tree) throws IOException {
|
||||
String name = nullSafeValue(tree.get("name"), String.class);
|
||||
int age = nullSafeValue(tree.get("age"), Integer.class);
|
||||
return new MyObject(name, age);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class MyObject {
|
||||
|
||||
MyObject(String name, int age) {
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
Integer getAge() {
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CorsConfiguration {
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer corsConfigurer() {
|
||||
return new WebMvcConfigurer() {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/api/**");
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.web.server.ErrorPage;
|
||||
import org.springframework.boot.web.server.ErrorPageRegistrar;
|
||||
import org.springframework.boot.web.server.ErrorPageRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@Configuration
|
||||
public class ErrorPageConfiguration {
|
||||
|
||||
@Bean
|
||||
public ErrorPageRegistrar errorPageRegistrar() {
|
||||
return this::registerErrorPages;
|
||||
}
|
||||
|
||||
private void registerErrorPages(ErrorPageRegistry registry) {
|
||||
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice(basePackageClasses = AcmeController.class)
|
||||
public class MyControllerAdvice extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ResponseBody
|
||||
@ExceptionHandler(MyException.class)
|
||||
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
|
||||
HttpStatus status = getStatus(request);
|
||||
return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);
|
||||
}
|
||||
|
||||
private HttpStatus getStatus(HttpServletRequest request) {
|
||||
Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
||||
HttpStatus status = HttpStatus.resolve(code);
|
||||
return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class AcmeController {
|
||||
|
||||
}
|
||||
|
||||
class MyException extends RuntimeException {
|
||||
|
||||
}
|
||||
|
||||
class MyErrorBody {
|
||||
|
||||
MyErrorBody(int value, String message) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
public class MyErrorViewResolver implements ErrorViewResolver {
|
||||
|
||||
@Override
|
||||
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
|
||||
// Use the request or status to optionally return a ModelAndView
|
||||
if (status == HttpStatus.INSUFFICIENT_STORAGE) {
|
||||
// We could add custom model values here
|
||||
new ModelAndView("myview");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class MyRestController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
|
||||
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/{user}")
|
||||
public User getUser(@PathVariable Long userId) {
|
||||
return this.userRepository.findById(userId).get();
|
||||
}
|
||||
|
||||
@GetMapping("/{user}/customers")
|
||||
List<Customer> getUserCustomers(@PathVariable Long userId) {
|
||||
return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{user}")
|
||||
public void deleteUser(@PathVariable Long userId) {
|
||||
this.userRepository.deleteById(userId);
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
interface UserRepository extends CrudRepository<User, Long> {
|
||||
|
||||
}
|
||||
|
||||
interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||
|
||||
List<Customer> findByUser(User user);
|
||||
|
||||
}
|
||||
|
||||
class User {
|
||||
|
||||
List<Customer> getCustomers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Customer {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.servlet;
|
||||
|
||||
//tag::code[]
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
@Configuration
|
||||
public class ServletFilterConfiguration {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<MyFilter> myFilter() {
|
||||
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter());
|
||||
// ...
|
||||
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
class MyFilter extends GenericFilterBean {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.webflux;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.boot.web.codec.CodecCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageReader;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CodecConfiguration {
|
||||
|
||||
@Bean
|
||||
public CodecCustomizer myCodecCustomizer() {
|
||||
return (configurer) -> {
|
||||
configurer.registerDefaults(false);
|
||||
configurer.customCodecs().register(new ServerSentEventHttpMessageReader());
|
||||
// ...
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.webflux;
|
||||
|
||||
//tag::code[]
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
|
||||
import org.springframework.boot.web.reactive.error.ErrorAttributes;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse.BodyBuilder;
|
||||
|
||||
@Component
|
||||
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
|
||||
|
||||
public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,
|
||||
ApplicationContext applicationContext) {
|
||||
super(errorAttributes, resources, applicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
|
||||
return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml);
|
||||
}
|
||||
|
||||
private boolean acceptsXml(ServerRequest request) {
|
||||
return request.headers().accept().contains(MediaType.APPLICATION_XML);
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) {
|
||||
BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
// ... additional builder calls
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.webflux;
|
||||
|
||||
//tag::code[]
|
||||
import java.util.List;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class MyRestController {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final CustomerRepository customerRepository;
|
||||
|
||||
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
|
||||
this.userRepository = userRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
}
|
||||
|
||||
@GetMapping("/{user}")
|
||||
public Mono<User> getUser(@PathVariable Long userId) {
|
||||
return this.userRepository.findById(userId);
|
||||
}
|
||||
|
||||
@GetMapping("/{user}/customers")
|
||||
Flux<Customer> getUserCustomers(@PathVariable Long userId) {
|
||||
return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{user}")
|
||||
public void deleteUser(@PathVariable Long userId) {
|
||||
this.userRepository.deleteById(userId);
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
|
||||
interface UserRepository extends ReactiveCrudRepository<User, Long> {
|
||||
|
||||
}
|
||||
|
||||
interface CustomerRepository extends ReactiveCrudRepository<Customer, Long> {
|
||||
|
||||
Flux<Customer> findByUser(User user);
|
||||
|
||||
}
|
||||
|
||||
class User {
|
||||
|
||||
List<Customer> getCustomers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Customer {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.webflux.fn;
|
||||
|
||||
//tag::code[]
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.DELETE;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
|
||||
import static org.springframework.web.reactive.function.server.RequestPredicates.accept;
|
||||
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RoutingConfiguration {
|
||||
|
||||
private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
|
||||
// @formatter:off
|
||||
return route(
|
||||
GET("/{user}").and(ACCEPT_JSON), userHandler::getUser).andRoute(
|
||||
GET("/{user}/customers").and(ACCEPT_JSON), userHandler::getUserCustomers).andRoute(
|
||||
DELETE("/{user}").and(ACCEPT_JSON), userHandler::deleteUser);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.springbootfeatures.webapplications.webflux.fn;
|
||||
|
||||
//tag::code[]
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
@Component
|
||||
public class UserHandler {
|
||||
|
||||
public Mono<ServerResponse> getUser(ServerRequest request) {
|
||||
// ...
|
||||
return ServerResponse.ok().build();
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
|
||||
// ...
|
||||
return ServerResponse.ok().build();
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> deleteUser(ServerRequest request) {
|
||||
// ...
|
||||
return ServerResponse.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
// end::code[]
|
||||
Reference in New Issue
Block a user