Spring Boot 错误页配置和全局异常处理

一、错误页配置

1.1 错误页控制器

package com.siniswift.efb.acars.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 错误页控制器
 *
 * @author: simon
 * @date: 2019/7/12 15:03
 */
@Controller
public class ErrorPageController {

    /**
     * 404错误页
     *
     * @return 404错误页
     */
    @RequestMapping("/error_404")
    public String page404View(){
        return "error/error404";
    }

    /**
     * 400错误页
     *
     * @return 400错误页
     */
    @RequestMapping("/error_400")
    public String page400View(){
        return "error/error400";
    }

    /**
     * 500错误页
     *
     * @return 500错误页
     */
    @RequestMapping("/error_500")
    public String page500View(){
        return "error/error500";
    }
}

1.2 新增错误页面

在/resources/templates/error目录下新增error400,error404,error500页面。以error400页面为例:




    
    400


400

1.3 spring boot 错误配置

Spring Boot默认使用嵌入式Tomcat,默认没有页面来处理404等常见错误。因此,为了给用户最佳的使用体验,404等常见错误需要我们自定义页面来处理。

在springboot2.0之前用org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer类来实现该功能。

package com.siniswift.efb.acars.config;

import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

/**
 * 错误页配置
 *
 * @author: simon
 * @date: 2019/7/12 15:11
 */
@Configuration
public class ErrorPageConfig {
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                ErrorPage error400Page = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error_400");
                ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error_404");
                ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error_500");

                container.addErrorPages(error400Page, error404Page, error500Page);
            }
        };
    }
}

在Spring Boot2.0以上配置嵌入式Servlet容器时EmbeddedServletContainerCustomizer类不存在,使用WebServerFactoryCustomizer接口替换EmbeddedServletContainerCustomizer组件完成对嵌入式Servlet容器的配置

    @Bean
    public WebServerFactoryCustomizer webServerFactoryCustomizer() {
        return new WebServerFactoryCustomizer() {
            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                // 对嵌入式servlet容器的配置
                // factory.setPort(8081);
                /* 注意:new ErrorPage(stat, path);中path必须是页面名称,并且必须“/”开始。
                    底层调用了String.java中如下方法:
                    public boolean startsWith(String prefix) {
                        return startsWith(prefix, 0);
                    }*/
                ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST,
                        "/error-400");
                ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND,
                        "/error-404");
                ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,
                        "/error-500");
                factory.addErrorPages(errorPage400, errorPage404,
                        errorPage500);
            }
        };
    }

二、全局异常处理

使用@ControllerAdvice处理全局异常

2.1 封装错误信息

package com.siniswift.efb.acars.utils;


import com.siniswift.efb.acars.enums.ResultEnum;

/**
 * 响应封装
 *
 * @author: simon
 * @date: 2019/3/26 16:16
 */
public class JsonResult {
    /**
     * 错误码
     */
    private int code;

    /**
     * 提示信息
     */
    private String msg;

    /**
     * 返回结果
     */
    private T data;

    /**
     * 成功时候的调用
     *
     * @param data 返回内容
     * @return 结果
     */
    public static  JsonResult success(T data) {
        return new JsonResult<>(data);
    }

    /**
     * 成功时候的调用
     *
     * @param msg 提示信息
     * @return 结果
     */
    public static  JsonResult success(String msg) {
        return new JsonResult<>(ResultEnum.SUCCESS.getCode(), msg);
    }

    /**
     * 成功时候的调用
     *
     * @param msg  提示信息
     * @param data 返回内容
     * @return 结果
     */
    public static  JsonResult success(String msg, T data) {
        return new JsonResult<>(ResultEnum.SUCCESS.getCode(), msg, data);
    }

    /**
     * 根据返回的状态对象构建返回结果
     *
     * @param resultEnum 返回结果枚举
     * @return 结果
     */
    public static  JsonResult build(ResultEnum resultEnum) {
        return new JsonResult<>(resultEnum);
    }

    /**
     * 根据code和msg构建返回结果
     *
     * @param code 结果代码
     * @param msg  提示信息
     * @return 结果
     */
    public static  JsonResult build(int code, String msg) {
        return new JsonResult<>(code, msg);
    }

    /**
     * 根据code,和msg,和data构建返回结果
     *
     * @param code 结果代码
     * @param msg  提示信息
     * @return 结果
     */
    public static  JsonResult build(int code, String msg, T data) {
        return new JsonResult<>(code, msg, data);
    }

    /**
     * 失败的调用
     *
     * @param msg 错误描述
     * @return 结果
     */
    public static  JsonResult error(String msg) {
        return new JsonResult<>(msg);
    }

    /**
     * 失败的调用,将返回结果传入
     *
     * @param data 返回内容
     * @return
     */
    public static  JsonResult error(T data) {
        return new JsonResult<>(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg(), data);
    }

    private JsonResult(T data) {
        this.code = ResultEnum.SUCCESS.getCode();
        this.msg = ResultEnum.SUCCESS.getMsg();
        this.data = data;
    }

    private JsonResult(String msg) {
        this.code = ResultEnum.ERROR.getCode();
        this.data = null;
        this.msg = msg;
    }

    private JsonResult(ResultEnum resultEnum) {
        this.code = resultEnum.getCode();
        this.msg = resultEnum.getMsg();
    }

    private JsonResult(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private JsonResult(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
package com.siniswift.efb.acars.enums;

/**
 * @author: simon
 * @date: 2019/3/26 16:35
 * @description: 返回结果枚举
 */
public enum ResultEnum {

    SUCCESS(0, "成功"),
    ERROR(-1, "失败");

    /**
     * 结果代码
     */
    private int code;
    /**
     * 结果描述
     */
    private String msg;

    ResultEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

2.2 全局异常处理

package com.siniswift.efb.acars.config;

import com.siniswift.efb.acars.utils.JsonResult;
import com.siniswift.efb.acars.utils.WebServiceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 全局异常捕获
 *
 * @author: simon
 * @date: 2019/3/26 16:15
 */
@CrossOrigin
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    /**
     * 提示消息模板
     */
    private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";

    /**
     * 日志
     */
    private static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public Object runtimeExceptionHandler(RuntimeException ex) {
        return exceptionFormat(1, ex);
    }

    /**
     * 空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    public Object nullPointerExceptionHandler(NullPointerException ex) {
        return exceptionFormat(2, ex);
    }

    /**
     * 类型转换异常
     */
    @ExceptionHandler(ClassCastException.class)
    public Object classCastExceptionHandler(ClassCastException ex) {
        return exceptionFormat(3, ex);
    }

    /**
     * IO异常
     */
    @ExceptionHandler(IOException.class)
    public Object iOExceptionHandler(IOException ex) {
        return exceptionFormat(4, ex);
    }

    /**
     * 未知方法异常
     */
    @ExceptionHandler(NoSuchMethodException.class)
    public Object noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return exceptionFormat(5, ex);
    }

    /**
     * 数组越界异常
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public Object indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return exceptionFormat(6, ex);
    }

    /**
     * 400错误
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Object requestNotReadable(HttpMessageNotReadableException ex) {
        return exceptionFormat(7, ex);
    }

    /**
     * 400错误
     */
    @ExceptionHandler({TypeMismatchException.class})
    public Object requestTypeMismatch(TypeMismatchException ex) {
        return exceptionFormat(8, ex);
    }

    /**
     * 400错误
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public Object requestMissingServletRequest(MissingServletRequestParameterException ex) {
        return exceptionFormat(9, ex);
    }

    /**
     * 405错误
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public Object request405(HttpRequestMethodNotSupportedException ex) {
        return exceptionFormat(10, ex);
    }

    /**
     * 406错误
     */
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public Object request406(HttpMediaTypeNotAcceptableException ex) {
        return exceptionFormat(11, ex);
    }

    /**
     * 500错误
     */
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public Object server500(RuntimeException ex) {
        return exceptionFormat(12, ex);
    }

    /**
     * 栈溢出
     */
    @ExceptionHandler({StackOverflowError.class})
    public Object requestStackOverflow(StackOverflowError ex) {
        return exceptionFormat(13, ex);
    }

    /**
     * 其他错误
     */
    @ExceptionHandler({Exception.class})
    public Object exception(Exception ex) {
        return exceptionFormat(14, ex);
    }

    private  Object exceptionFormat(Integer code, T ex) {
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        //获取request对象
        HttpServletRequest request = WebServiceUtils.getRequest();
        if(isAjax(request)){
            return JsonResult.build(code, ex.getMessage());
        }else{
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("error/error404");
            return modelAndView;
        }
    }

    /**
     * 判断是否是Ajax请求
     *
     * @param request 请求对象
     * @return 0:否;1:是
     */
    private boolean isAjax(HttpServletRequest request) {
        return (request.getHeader("X-Requested-With") != null &&
                "XMLHttpRequest".equals(request.getHeader("X-Requested-With")));
    }
}

}

你可能感兴趣的:(Spring,Boot,2.0)