当用户在Spring启动应用程序中输入无效URL时,如何显示自定义404页面?

时间:2016-03-12 11:25:48

标签: java spring spring-security spring-boot

我在spring boot,spring安全应用程序中使用java config。我已将错误控制器配置如下。但每当我输入一个无效的URL时,它会转到error.jsp,它被配置为处理应用程序中的错误:

@Controller
public class AppErrorController implements ErrorController {

    private static final String PATH = "/error";

    @RequestMapping(value = "/pageNotFound", method = { RequestMethod.GET, RequestMethod.POST })
    public String pageNotFound() {
        return "pageNotFound";
    }

    @RequestMapping(value = "/accessDenied", method = { RequestMethod.GET, RequestMethod.POST })
    public String accessDenied() {
        return "accessDenied";
    }

    @RequestMapping(value = PATH)
    public String error() {
        return "error";
    }

    @Override
    public String getErrorPath() {
        return PATH;
    }
}

的web.xml

<error-page>
    <error-code>404</error-code>
    <location>/pageNotFound</location>
</error-page>

<error-page>
    <error-code>500</error-code>
    <location>/error</location>
</error-page>
输入无效网址时,永远不会抛出

另外,我没有使用嵌入式tomcat。我正在向外部tomcat部署战争。我在application.yml文件中有这个:

server:
    error:
        whitelabel:
            enabled: false

以下是输入无效网址时的登录信息。没有错误。如果网址无效,它只会重定向到/error

2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.b.c.web.OrderedRequestContextFilter  : Bound request context to thread: org.apache.catalina.connector.RequestFacade@371ef2a3
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/donotexisturl'; against '/static/**'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/donotexisturl'; against '/i18n/**'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@b8db0c9d: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b8db0c9d: Principal: User{id=8, firstname='Adam', lastname='Milne', email='adam.milne@abcd.com', roleId=1}; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: FED1F23633671F6E257CA9C5AFCEE216; Granted Authorities: ModuleOperation{moduleOperationId=1, moduleOperationName='roleList', moduleId=2, moduleName='role'}, ModuleOperation{moduleOperationId=8, moduleOperationName='deleteUser', moduleId=1, moduleName='user'}'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@6e929f31
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /donotexisturl' doesn't match 'POST /logout
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-03-15 10:02:45.061 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /donotexisturl' doesn't match 'POST /checklogin
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 7 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.AnonymousAuthenticationFilter  : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b8db0c9d: Principal: User{id=8, firstname='Adam', lastname='Milne', email='adam.milne@abcd.com', roleId=1}; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: FED1F23633671F6E257CA9C5AFCEE216; Granted Authorities: ModuleOperation{moduleOperationId=1, moduleOperationName='roleList', moduleId=2, moduleName='role'}, ModuleOperation{moduleOperationId=8, moduleOperationName='deleteUser', moduleId=1, moduleName='user'}'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /donotexisturl' doesn't match 'POST /logout
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/donotexisturl'; against '/login**'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/donotexisturl'; against '/error**'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/donotexisturl'; against '/checklogin**'
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /doNotExistURL; Attributes: [fullyAuthenticated]
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b8db0c9d: Principal: User{id=8, firstname='Adam', lastname='Milne', email='adam.milne@abcd.com', roleId=1}; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: FED1F23633671F6E257CA9C5AFCEE216; Granted Authorities: ModuleOperation{moduleOperationId=1, moduleOperationName='roleList', moduleId=2, moduleName='role'}, ModuleOperation{moduleOperationId=8, moduleOperationName='deleteUser', moduleId=1, moduleName='user'}
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.access.vote.UnanimousBased  : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@6ad88564, returned: 1
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.access.vote.UnanimousBased  : Voter: org.springframework.security.access.vote.AuthenticatedVoter@19007bb6, returned: 0
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.access.vote.UnanimousBased  : Voter: com.sts.app.core.user.security.AccessDecisionVoterImpl@1465b821, returned: 1
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /doNotExistURL reached end of additional filter chain; proceeding with original chain
2016-03-15 10:02:45.062 DEBUG 9997 --- [io-8080-exec-22] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/gen/doNotExistURL]
2016-03-15 10:02:45.063 DEBUG 9997 --- [io-8080-exec-22] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /doNotExistURL
2016-03-15 10:02:45.064 DEBUG 9997 --- [io-8080-exec-22] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/doNotExistURL]
2016-03-15 10:02:45.064 DEBUG 9997 --- [io-8080-exec-22] o.s.w.s.handler.SimpleUrlHandlerMapping  : Matching patterns for request [/doNotExistURL] are [/**]
2016-03-15 10:02:45.064 DEBUG 9997 --- [io-8080-exec-22] o.s.w.s.handler.SimpleUrlHandlerMapping  : URI Template variables for request [/doNotExistURL] are {}
2016-03-15 10:02:45.064 DEBUG 9997 --- [io-8080-exec-22] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapping [/doNotExistURL] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[ServletContext resource [/], class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@87dd2cb]]] and 1 interceptor
2016-03-15 10:02:45.064 DEBUG 9997 --- [io-8080-exec-22] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/gen/doNotExistURL] is: -1
2016-03-15 10:02:45.077 DEBUG 9997 --- [io-8080-exec-22] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.web.servlet.DispatcherServlet        : Successfully completed request
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.b.c.web.OrderedRequestContextFilter  : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@371ef2a3
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.b.c.web.OrderedRequestContextFilter  : Bound request context to thread: org.apache.catalina.core.ApplicationHttpRequest@20ae74b1
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/static/**'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/error'; against '/i18n/**'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] w.c.HttpSessionSecurityContextRepository : Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@b8db0c9d: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b8db0c9d: Principal: User{id=8, firstname='Adam', lastname='Milne', email='adam.milne@abcd.com', roleId=1}; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: FED1F23633671F6E257CA9C5AFCEE216; Granted Authorities: ModuleOperation{moduleOperationId=1, moduleOperationName='roleList', moduleId=2, moduleName='role'}, ModuleOperation{moduleOperationId=8, moduleOperationName='deleteUser', moduleId=1, moduleName='user'}'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 4 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /error' doesn't match 'POST /logout
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 6 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2016-03-15 10:02:45.078 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /error' doesn't match 'POST /checklogin
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 7 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.s.w.a.AnonymousAuthenticationFilter  : SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@b8db0c9d: Principal: User{id=8, firstname='Adam', lastname='Milne', email='adam.milne@abcd.com', roleId=1}; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: FED1F23633671F6E257CA9C5AFCEE216; Granted Authorities: ModuleOperation{moduleOperationId=1, moduleOperationName='roleList', moduleId=2, moduleName='role'}, ModuleOperation{moduleOperationId=8, moduleOperationName='deleteUser', moduleId=1, moduleName='user'}'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.security.web.FilterChainProxy        : /error reached end of additional filter chain; proceeding with original chain
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/gen/error]
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2016-03-15 10:02:45.079 DEBUG 9997 --- [io-8080-exec-22] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String com.sts.app.core.common.web.AppErrorController.error()]

4 个答案:

答案 0 :(得分:4)

首先,为您要处理的每个特殊HTTP错误定义一个例外。在这里,我只是定义一个处理404 Not Found案例:

public class NotFoundException extends RuntimeException {}

要完全替换默认的Spring Boot的错误处理机制,我们可以实现ErrorController。我不是仅仅实现ErrorController,而是扩展AbstractErrorController,实现ErrorController并提供一些辅助方法,如getStatus()

无论如何,基本的想法是使用端点处理所有错误,比如/error,并在相应的HTTP状态代码的情况下抛出这些预定义的异常:

@Controller
public class CustomErrorController extends AbstractErrorController {
    private static final String ERROR_PATH=  "/error";

    @Autowired
    public CustomErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes);
    }

    /**
     * Just catching the {@linkplain NotFoundException} exceptions and render
     * the 404.jsp error page.
     */
    @ExceptionHandler(NotFoundException.class)
    public String notFound() {
        return "404";
    }

    /**
     * Responsible for handling all errors and throw especial exceptions
     * for some HTTP status codes. Otherwise, it will return a map that
     * ultimately will be converted to a json error.
     */
    @RequestMapping(ERROR_PATH)
    public ResponseEntity<?> handleErrors(HttpServletRequest request) {
        HttpStatus status = getStatus(request);

        if (status.equals(HttpStatus.NOT_FOUND))
            throw new NotFoundException();

        return ResponseEntity.status(status).body(getErrorAttributes(request, false));
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}

当然,此解决方案仅适用于传统部署。如果您计划使用嵌入式Servlet容器,则最好定义EmbeddedServletContainerCustomizer

答案 1 :(得分:3)

您是否希望将此@Bean添加到spring应用程序配置中,如下所示:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return new EmbeddedServletContainerCustomizer() {
        @Override
        public void customize(ConfigurableEmbeddedServletContainer container) {

            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error404.html");
            container.addErrorPages(error404Page);

        }
    };
}

并将error404.html放入静态文件夹。

参考: http://www.sporcic.org/2014/05/custom-error-pages-with-spring-boot/

答案 2 :(得分:0)

你去吧

@RestController
public class RestErrorController implements ErrorController{

private static final String PATH = "/error";

@Autowired
private ErrorAttributes errorAttributes;

@RequestMapping(value=PATH,method=RequestMethod.GET)
public ApiErrorExtended error(HttpServletRequest request, HttpServletResponse response){
     return new ApiErrorExtended( response.getStatus(),getErrorAttributes(request, true));
}

private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
    RequestAttributes requestAttributes = new ServletRequestAttributes(request);
    return errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
}  

public String getErrorPath() {
    return PATH;
} 
}

这是我的休息错误控制器。您可以修改它以返回您想要的任何内容。

答案 3 :(得分:0)

嗨,您只需要配置以下内容:

<error-page>
     <error-code>404</error-code>
     <location>/pageNotFound/404.jsp</location>
 </error-page>

并配置Java异常:

<error-page>
 <exception-type>java.lang.Exception</exception-type>
 <location>/pageNotFound/exception.jsp</location>