springboot 對異常的統一處理方法

在spring boot 中,Controller 中拋出的異常默認交給 /error  來處理(Controller 中匹配此路徑的方法),應用程序可以將 /error 映射到一個特定的Controller  中處理,應用可以繼承 AbstractErrorController 來統一處理系統的各種異常。

請看下面代碼,有解釋。讀者可以複製這段代碼到項目中,故意拋出異常來測試,代碼中示例的頁面error.btl 讀者請自己寫。btl 即beetl ,是一種頁面技術,類似freemarker和jsp。

@RestController
public class ErrorController extends AbstractErrorController {
    Log log = LogFactory.getLog(ErrorController.class);

    /**
     * 因爲繼承的AbstractErrorController沒有無參數構造器,所以要添加這個構造器
     * @param errorAttributes
     */
    public ErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes);
    }

    @RequestMapping("error")
    public ModelAndView getErrorPath(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> model =
                Collections.unmodifiableMap(getErrorAttributes(request, false));
        //獲取異常,有可能爲空
        Throwable cause = getCause(request);
        int status = (Integer) model.get("status");
        //錯誤信息
        String message = (String) model.get("message");
        //友好提示
        String errorMessage = getErrorMessage(cause);
        //後臺打印日誌信息方便差錯
        log.info(status + "," + message, cause);
        response.setStatus(status);
        if (!isJsonRequest(request)) {
            //error.btl 顯示詳細的錯誤信息。這個頁面您自己寫,根據下面的屬性獲取信息。
            ModelAndView view = new ModelAndView("/error.btl");
            view.addAllObjects(model);
            view.addObject("errorMessage", errorMessage);
            view.addObject("status", status);
            view.addObject("cause", cause);
            view.addObject("message", message);
            return view;
        } else {
            //如果請求是json 類型數據
            Map error = new HashMap();
            error.put("success", false);
            error.put("errorMessage", errorMessage);
            error.put("message", message);
            //writeJson(response,error);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            try {
                response.getWriter().write(error.toString());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    /**
     * 獲取通俗的異常信息給用戶
     * @param ex
     * @return
     */
    protected String getErrorMessage(Throwable ex) {
        return "服務器錯誤,請聯繫管理員。";
    }

    /**
     * 獲取異常的具體信息
     * @param request
     * @return Throwable
     */
    protected Throwable getCause(HttpServletRequest request) {
        Throwable error = (Throwable) request.getAttribute("javax.servlet.error.exception");
        if (error != null) {
            while (error instanceof ServletException && error.getCause() != null) {
                error = ((ServletException) error).getCause();
            }
        }
        return error;
    }

    /**
     * 判斷response 請求的是否json 類型
     * @param request
     * @return boolean
     */
    protected boolean isJsonRequest(HttpServletRequest request) {
        String requestURI = (String) request.getAttribute("javax.servlet.error.request_uri");
        String header = request.getHeader("Accept");
        if (requestURI != null && requestURI.endsWith(".json")) {
            return true;
        } else if (header.contains("application/json")) {
            return true;
        } else {
            return false;
        }
    }

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

把本人簡易的錯誤展示頁面 error.btl 貼一下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>error message</title>
</head>
<body>
 <h5>error message</h5>
 <p>${status}</p>
 <p>${errorMessage}</p>
 <p>${cause}</p>
 <p>${message}</p>
</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章