/* * Copyright 2002-2017 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 * * http://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.web.reactive.config; import java.util.HashMap; import java.util.List; import java.util.Map; import reactor.core.publisher.Mono; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.annotation.Order; import org.springframework.core.convert.converter.Converter; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.util.ClassUtils; import org.springframework.validation.Errors; import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.accept.CompositeContentTypeResolver; import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder; import org.springframework.web.reactive.handler.AbstractHandlerMapping; import org.springframework.web.reactive.result.SimpleHandlerAdapter; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; import org.springframework.web.reactive.result.method.annotation.ResponseEntityResultHandler; import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebExceptionHandler; import org.springframework.web.server.handler.ResponseStatusExceptionHandler; /** * The main class for Spring WebFlux configuration. * *
Import directly or extend and override protected methods to customize.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class WebFluxConfigurationSupport implements ApplicationContextAware {
static final boolean jackson2Present =
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
WebFluxConfigurationSupport.class.getClassLoader()) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
WebFluxConfigurationSupport.class.getClassLoader());
private Map Use {@link #configureHttpMessageCodecs(ServerCodecConfigurer)} to
* configure the readers and writers.
*/
@Bean
public ServerCodecConfigurer serverCodecConfigurer() {
ServerCodecConfigurer serverCodecConfigurer = ServerCodecConfigurer.create();
configureHttpMessageCodecs(serverCodecConfigurer);
return serverCodecConfigurer;
}
/**
* Override to configure the HTTP message readers and writers to use.
*/
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
}
/**
* Return the {@link ConfigurableWebBindingInitializer} to use for
* initializing all {@link WebDataBinder} instances.
*/
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(webFluxConversionService());
initializer.setValidator(webFluxValidator());
initializer.setMessageCodesResolver(getMessageCodesResolver());
return initializer;
}
@Bean
public FormattingConversionService webFluxConversionService() {
FormattingConversionService service = new DefaultFormattingConversionService();
addFormatters(service);
return service;
}
/**
* Override to add custom {@link Converter}s and {@link Formatter}s.
*/
protected void addFormatters(FormatterRegistry registry) {
}
/**
* Return a {@link ReactiveAdapterRegistry} to adapting reactive types.
*/
@Bean
public ReactiveAdapterRegistry webFluxAdapterRegistry() {
return new ReactiveAdapterRegistry();
}
/**
* Return a global {@link Validator} instance for example for validating
* {@code @RequestBody} method arguments.
* Delegates to {@link #getValidator()} first. If that returns {@code null}
* checks the classpath for the presence of a JSR-303 implementations
* before creating a {@code OptionalValidatorFactoryBean}. If a JSR-303
* implementation is not available, a "no-op" {@link Validator} is returned.
*/
@Bean
public Validator webFluxValidator() {
Validator validator = getValidator();
if (validator == null) {
if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
Class> clazz;
try {
String name = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
clazz = ClassUtils.forName(name, getClass().getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException("Could not find default validator class", ex);
}
catch (LinkageError ex) {
throw new BeanInitializationException("Could not load default validator class", ex);
}
validator = (Validator) BeanUtils.instantiateClass(clazz);
}
else {
validator = new NoOpValidator();
}
}
return validator;
}
/**
* Override this method to provide a custom {@link Validator}.
*/
protected Validator getValidator() {
return null;
}
/**
* Override this method to provide a custom {@link MessageCodesResolver}.
*/
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return new SimpleHandlerAdapter();
}
@Bean
public ResponseEntityResultHandler responseEntityResultHandler() {
return new ResponseEntityResultHandler(serverCodecConfigurer().getWriters(),
webFluxContentTypeResolver(), webFluxAdapterRegistry());
}
@Bean
public ResponseBodyResultHandler responseBodyResultHandler() {
return new ResponseBodyResultHandler(serverCodecConfigurer().getWriters(),
webFluxContentTypeResolver(), webFluxAdapterRegistry());
}
@Bean
public ViewResolutionResultHandler viewResolutionResultHandler() {
ViewResolverRegistry registry = new ViewResolverRegistry(getApplicationContext());
configureViewResolvers(registry);
List