Move ErrorController to autoconfig

pull/746/merge
Dave Syer 11 years ago
parent 27580e726f
commit ef4e83a879

@ -31,10 +31,10 @@ import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainer;

@ -22,14 +22,11 @@ import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -43,12 +40,12 @@ import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
import org.springframework.boot.autoconfigure.security.SecurityPrequisite;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
@ -56,12 +53,9 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity.I
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* {@link EnableAutoConfiguration Auto-configuration} for security of framework endpoints.
@ -91,19 +85,6 @@ public class ManagementSecurityAutoConfiguration {
return new IgnoredPathsWebSecurityConfigurerAdapter();
}
@ConditionalOnWebApplication
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
protected static class SecurityExceptionRethrowingAdvice {
@ExceptionHandler({ AccessDeniedException.class, AuthenticationException.class })
public void handle(HttpServletRequest request, HttpServletResponse response,
Exception e) throws Exception {
throw e;
}
}
@Configuration
protected static class ManagementSecurityPropertiesConfiguration implements
SecurityPrequisite {

@ -24,10 +24,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.actuate.trace.WebRequestTraceFilter;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.web.BasicErrorController;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@ -19,7 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;

@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.boot.autoconfigure.web.BasicErrorController;
import org.springframework.core.Ordered;
import org.springframework.web.context.request.ServletRequestAttributes;

@ -5,7 +5,6 @@ org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.JolokiaAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ErrorMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\

@ -29,6 +29,7 @@ import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;

@ -19,7 +19,7 @@ package org.springframework.boot.actuate.trace;
import java.util.Map;
import org.junit.Test;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.boot.autoconfigure.web.BasicErrorController;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

@ -20,6 +20,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -34,6 +37,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
@ -47,10 +51,13 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
/**
@ -102,6 +109,18 @@ public class SpringBootWebSecurityConfiguration {
return new IgnoredPathsWebSecurityConfigurerAdapter();
}
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
protected static class SecurityExceptionRethrowingAdvice {
@ExceptionHandler({ AccessDeniedException.class, AuthenticationException.class })
public void handle(HttpServletRequest request, HttpServletResponse response,
Exception e) throws Exception {
throw e;
}
}
public static void configureHeaders(HeadersConfigurer<?> configurer,
SecurityProperties.Headers headers) throws Exception {
if (headers.getHsts() != Headers.HSTS.none) {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web;
package org.springframework.boot.autoconfigure.web;
import java.io.PrintWriter;
import java.io.StringWriter;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web;
package org.springframework.boot.autoconfigure.web;
import java.util.Map;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure;
package org.springframework.boot.autoconfigure.web;
import java.util.HashMap;
import java.util.Map;
@ -24,8 +24,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.actuate.web.BasicErrorController;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
@ -36,7 +34,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration.DefaultTemplateResolverConfiguration;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.ErrorPage;

@ -32,4 +32,5 @@ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration

@ -20,8 +20,8 @@ import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import org.springframework.boot.SimpleMainTests;
import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactoryTests;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfigurationTests;
import org.springframework.boot.autoconfigure.web.DefaultErrorViewIntegrationTests;
/**
* A test suite for probing weird ordering problems in the tests.
@ -29,7 +29,8 @@ import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletConta
* @author Dave Syer
*/
@RunWith(Suite.class)
@SuiteClasses({ SimpleMainTests.class, JettyEmbeddedServletContainerFactoryTests.class })
@SuiteClasses({ DefaultErrorViewIntegrationTests.class,
SecurityAutoConfigurationTests.class })
@Ignore
public class AdhocTestSuite {

@ -114,6 +114,8 @@ public class SecurityAutoConfigurationTests {
public void testJpaCoexistsHappily() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.url:jdbc:hsqldb:mem:testsecdb");
this.context.register(EntityConfiguration.class,
PropertyPlaceholderAutoConfiguration.class,
DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web;
package org.springframework.boot.autoconfigure.web;
import java.util.Map;
@ -28,16 +28,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration;
import org.springframework.boot.actuate.web.BasicErrorControllerIntegrationTests.TestConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.BasicErrorControllerIntegrationTests.TestConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
@ -61,6 +62,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@DirtiesContext
public class BasicErrorControllerIntegrationTests {
@Autowired
@ -117,8 +119,7 @@ public class BasicErrorControllerIntegrationTests {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class })
DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public static class TestConfiguration {
// For manual testing

@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web;
package org.springframework.boot.autoconfigure.web;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.EndpointMBeanExportAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Configuration;
@ -82,16 +82,14 @@ public class BasicErrorControllerSpecialIntegrationTests {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class })
HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
protected static class ParentConfiguration {
}
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class })
HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
@EnableWebMvc
protected static class WebMvcIncludedConfiguration {
// For manual testing
@ -103,10 +101,9 @@ public class BasicErrorControllerSpecialIntegrationTests {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class })
HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
protected static class VanillaConfiguration {
// For manual testing
// For manual testingm
public static void main(String[] args) {
SpringApplication.run(VanillaConfiguration.class, args);
}
@ -115,8 +112,7 @@ public class BasicErrorControllerSpecialIntegrationTests {
@Configuration
@EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointMBeanExportAutoConfiguration.class })
HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
protected static class ChildConfiguration {
// For manual testing
public static void main(String[] args) {

@ -14,18 +14,19 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web;
package org.springframework.boot.autoconfigure.web;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.web.DefaultErrorViewIntegrationTests.TestConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.web.DefaultErrorViewIntegrationTests.TestConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
@ -43,6 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@DirtiesContext
public class DefaultErrorViewIntegrationTests {
@Autowired

@ -1150,7 +1150,7 @@ a `View` that resolves with a name of `error`, and/or a `@Controller` that handl
`/error` path. Unless you replaced some of the default configuration you should find a
`BeanNameViewResolver` in your `ApplicationContext` so a `@Bean` with id `error` would be
a simple way of doing that.
Look at {sc-spring-boot-actuator}/autoconfigure/ErrorMvcAutoConfiguration.{sc-ext}[`ErrorMvcAutoConfiguration`] for more options.
Look at {sc-spring-boot-autoconfigure}/web/ErrorMvcAutoConfiguration.{sc-ext}[`ErrorMvcAutoConfiguration`] for more options.

@ -737,43 +737,6 @@ the capacity. You can also create your own alternative `TraceRepository` impleme
if needed.
[[production-ready-error-handling]]
== Error Handling
Spring Boot Actuator provides an `/error` mapping by default that handles all errors in a
sensible way, and it is registered as a ``global'' error page in the servlet container.
For machine clients it will produce a JSON response with details of the error, the HTTP
status and the exception message. For browser clients there is a ``whitelabel'' error
view that renders the same data in HTML format (to customize it just add a `View` that
resolves to ``error'').
If you want more specific error pages for some conditions, the embedded servlet containers
support a uniform Java DSL for customizing the error handling. For example:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new MyCustomizer();
}
// ...
private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer factory) {
factory.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
----
You can also use regular Spring MVC features like http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exception-handlers[`@ExceptionHandler`
methods] and http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-controller-advice[`@ControllerAdvice`].
[[production-ready-process-monitoring]]
== Process monitoring
In Spring Boot Actuator you can find `ApplicationPidListener` which creates file

@ -906,6 +906,41 @@ TIP: JSPs should be avoided if possible, there are several
servlet containers.
[[boot-features-error-handling]]
==== Error Handling
Spring Boot provides an `/error` mapping by default that handles all errors in a
sensible way, and it is registered as a ``global'' error page in the servlet container.
For machine clients it will produce a JSON response with details of the error, the HTTP
status and the exception message. For browser clients there is a ``whitelabel'' error
view that renders the same data in HTML format (to customize it just add a `View` that
resolves to ``error'').
If you want more specific error pages for some conditions, the embedded servlet containers
support a uniform Java DSL for customizing the error handling. For example:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new MyCustomizer();
}
// ...
private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer factory) {
factory.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
----
You can also use regular Spring MVC features like http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exception-handlers[`@ExceptionHandler`
methods] and http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-controller-advice[`@ControllerAdvice`].
[[boot-features-embedded-container]]
=== Embedded servlet container support

Loading…
Cancel
Save