SpringBoot自定义错误页

在内嵌容器为tomcat的情况下,springboot一个请求发生内部错误需要调用错误页时,其实是在StandardHostValve里查找错误页,再触发一次错误页请求调用。具体代码如下

public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    ......
    Throwable t = (Throwable) 
    request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);

    // Protect against NPEs if the context was destroyed during a
    // long running request.
    if (!context.getState().isAvailable()) {
        return;
    }

    // Look for (and render if found) an application level error page
    if (response.isErrorReportRequired()) {
        if (t != null) {
           throwable(request, response, t);
        } else {
                    status(request, response);
        }
     }
    ......
}


  private void status(Request request, Response response) {

        int statusCode = response.getStatus();

        // Handle a custom error page for this status code
        Context context = request.getContext();
        if (context == null) {
            return;
        }

        /* Only look for error pages when isError() is set.
         * isError() is set when response.sendError() is invoked. This
         * allows custom error pages without relying on default from
         * web.xml.
         */
        if (!response.isError()) {
            return;
        }
        //根据错误码查找已注册的错误页
        ErrorPage errorPage = context.findErrorPage(statusCode);
        if (errorPage == null) {
            //注意这里,springboot默认只注册一个错误页/error,所以在默认情况下
            //所有异常错误码都会跳转到/error
            // Look for a default error page
            errorPage = context.findErrorPage(0);
        }
        ......
}

默认情况下,springboot只注册一个错误页/error,因此查找错误码页时不会找到任何匹配的,只能跳转到/error。springboot内注册错误页是通过添加ErrorPageRegistrar实现的

private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
		for (ErrorPageRegistrar registrar : getRegistrars()) {
			registrar.registerErrorPages(registry);
		}
	}

	private Collection<ErrorPageRegistrar> getRegistrars() {
		if (this.registrars == null) {
			// Look up does not include the parent context
			this.registrars = new ArrayList<>(this.beanFactory
					.getBeansOfType(ErrorPageRegistrar.class, false, false).values());
			this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.registrars = Collections.unmodifiableList(this.registrars);
		}
		return this.registrars;
	}

所以我们要在springboot环境内注册自己的错误码配置的话,添加一个自定义的ErrorPageRegistrar就可以了。为了方便起见,我把错误码定义和错误页配置放一起了,只要把下面的代码拷到任意一个Controller里就可以了

    @Bean
    public ErrorPageRegistrar errorPageRegistrar(){
        return registry -> {
            registry.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/500"));
            registry.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,"/404"));
            registry.addErrorPages(new ErrorPage(HttpStatus.FORBIDDEN,"/403"));
            registry.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED,"/401"));
        };
    }

    @RequestMapping("/500")
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public RequestResult error500(HttpServletRequest request){
        Map<String, Object> body = getErrorAttributes(request,true);
        return new RequestResult(false,"服务器异常",body);
    }

    @RequestMapping("/404")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public RequestResult error404(HttpServletRequest request){
        Map<String, Object> body = getErrorAttributes(request,true);
        return new RequestResult(false,"无此路径:"+body.get("path"));
    }

    @RequestMapping("/403")
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public RequestResult error403(HttpServletRequest request){
        Map<String, Object> body = getErrorAttributes(request,true);
        return new RequestResult(false,"无此资源访问权限:"+body.get("path"));
    }

    @RequestMapping("/401")
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public RequestResult error401(HttpServletRequest request){
        Map<String, Object> body = getErrorAttributes(request,true);
        return new RequestResult(false,"未授权的访问:"+body.get("path"));
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值