SpringBoot:Web項目中如何優(yōu)雅的同時處理Json和Html請求的異常

在一個web項目開發(fā)中,通常都會涉及到Html和Json請求。當出現(xiàn)異常的時候,我們需要根據(jù)請求類型返回不同的信息。如果是Json請求,那么就返回String或者ReponseEntity類型;如果是html請求,就要返回ModelAndView的錯誤頁面。

我們當然可以對Controller的每個接口方法拋出的異常單獨處理。但這樣做會導致大量的重復工作。Spring MVC為我們提供了@ControllerAdvice和@ExceptionHandler`兩個注解來實現(xiàn)全局的異常處理。關(guān)于這兩個注解的用法可以參考這里

這解決了大部分的問題,但是如果同一個Controller中既有html又有json接口方法怎么辦呢?我們當然可以拆分成兩個Controller,一個包含html接口,另一個包含json接口。但是這樣做不夠靈活,而且我更習慣根據(jù)業(yè)務邏輯來歸類接口。有沒有更好的方法呢?

其實在寫異常處理方法時,我們可以將請求信息作為參數(shù)傳入,并根據(jù)請求類型來返回不同的數(shù)據(jù)。

public class BaseController{
    private Boolean isJson(HttpServletRequest request){
        String header = request.getHeader("content-type");
        return header != null && header.contains("json");
    }

    @Override
    @ExceptionHandler(BaseException.class)
    public Object handleBaseException(HttpServletRequest request, baseException e) {
        if(isJson(request)) {
            return ResponseUtils.restResponse(
                    e.getCode(),
                    e.getMessage(),
                    e.getStatus()
            );
        } else {
            ModelAndView modelAndView = initModelAndView();
            if (e.getCode().equalsIgnoreCase("login_first")) {
                modelAndView.setViewName("redirect:/list");
            }
            if (e.getCode().equalsIgnoreCase("real_name_not_set")) {
                modelAndView.setViewName("redirect:/account");
            }else{
                modelAndView.setViewName("/404");
            }
            modelAndView.addObject("exception", e);
            return modelAndView;
        }
    }
}

這里我們寫了一個BaseController,并在Controller中實現(xiàn)了異常捕獲的邏輯。isJson()通過判斷請求的Content-Type是否包含json字符串來判斷該請求類型。當然,更好更合適的方式是通過包頭中的Accept中的信息類判斷。需要注意的是handleBaseException()方法返回了Object類型,這樣我們就可以根據(jù)需要返回不同類型的數(shù)據(jù)了。以后只要Contrller繼承BaseController就不用再考慮異常的問題了。

但是,如果異常是在進入接口方法之前被拋出的呢。比如404,406錯誤,根本不會執(zhí)行接口方法,因此也無法被ExceptionHandler捕獲。這部分異常如何處理呢?

Spring Boot提供了一個統(tǒng)一的/error地址用于所有未被捕獲的異常拋出。默認設(shè)置下顯示的是一個whitelabel error page。

通過實現(xiàn)ErrorController,我們可以定制這個錯誤頁面。

@Controller
public class MpErrorController extends BaseController implements ErrorController {
    private static final String PATH = "/error";

    @RequestMapping(value = PATH)
    public Object error() throws Exception {
        throw new BaseException();
    }

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

我們希望這個error頁面也根據(jù)請求的類型做出不同的邏輯處理。因此,可以直接在error()拋出BaseException異常,并且讓這個Controller繼承于BaseController。這樣,被拋出的異常也會被handleBaseException()捕獲了。

至此,我們比較優(yōu)雅的實現(xiàn)了全局的異常處理。所有的BaseException異常處理邏輯都集中在handleBaseException()方法中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • PS: 本文講得比較細,所以篇幅較長。 閱讀時間:30m~1h。請認真讀完,希望你一小時后能對統(tǒng)一異常處理有一個清...
    sprainkle閱讀 19,997評論 21 157
  • 前端一直是距離用戶最近的一層,隨著產(chǎn)品的日益完善,我們會更加注重用戶體驗,而前端異常卻如鯁在喉,甚是煩人。 一、為...
    勿忘巛心安閱讀 486評論 0 0
  • 在具體的SSM項目開發(fā)中,由于Controller層為處于請求處理的最頂層,再往上就是框架代碼的。因此,肯定需要在...
    Java大生閱讀 578評論 0 0
  • 最近不太平,流感病毒來不停。每天帶著口罩上班,預防感染和被感染。 我是一個超弱體質(zhì)的人,感冒是家常便飯,加上過敏性...
    明天陽光閱讀 435評論 0 3
  • 下班回家,見孩子臉色難看,剛一問眼淚就撲簌的往下掉。甭說,又鬧小情緒啦! 趕忙坐下來問了問情況,原來還是昨天那件事...
    禪貓癡語閱讀 242評論 0 0

友情鏈接更多精彩內(nèi)容