SpringBoot專案實戰(7):自定義異常處理介面

choubou發表於2021-09-09

在一般專案中都會有400、500和404這種的異常頁面,針對每個異常頁面都會設計相應的頁面佈局和樣式,也只有這樣的錯誤頁面才會讓普通使用者看著容易接受,而不是程式出錯後將異常程式碼暴露在頁面上,這種的使用者體驗...額,這種壓根就沒有使用者體驗這一說!
比如:圖片描述
和:圖片描述

相對來說第二種對使用者來說就顯得沒那麼"害怕"了。(原諒我用害怕這個詞)

其實在Springboot中,SB是預設把異常的處理都集中到了一個ModelAndView中
圖片描述

上圖是Springboot專案啟動時各個路徑的對映情況, 可以看到,預設是有兩個error對映的,其中一個是針對json一個是針對html頁面的。其中這些對映都是在BasicErrorController這個類下,如下圖:
圖片描述

它是統一跳轉到error這個頁面了。

再來看下我們本地的controller

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @RequestMapping("/")
    public String home(Model model) {
        return "index";
    }

    @RequestMapping("/error500")
    public void index() {
        int a = 1 / 0;
        System.out.println(a);
    }

    @RequestMapping("/error400/{id}")
    public Object error400(@PathVariable("id") Integer id) {
        System.out.println(id);
        return id;
    }

}

如上圖,在訪問error500的時候一定會報500,在訪問error400/a時一定會報400,
新增error頁面(在error頁面中已經指定了"這是預設的error頁面"),
圖片描述

那麼在系統異常時就會跳到這個error頁面:
圖片描述
圖片描述
圖片描述

那麼,應該怎麼做才能讓具體的異常處理頁面分離開呢?

切入正題,SpringBoot中有ConfigurableEmbeddedServletContainer介面(它繼承自ErrorPageRegistry),
圖片描述
圖片描述

ErrorPageRegistry
圖片描述
上面兩幅圖是這個介面下的部分方法,可以看到,透過這個介面可以對SpringBoot程式進行很大程度的自定義控制,比如程式埠、session有效期等等。今天用到的就是上面最後一張圖中的addErrorPages方法。

@Component
public class AppErrorPagesConfiguration {

    /**
     * 自定義異常處理路徑
     * @return
     */
    @Bean
    public EmbeddedServletContainerCustomizer containerCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
                configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"));
                configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400"));
                configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
                configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(java.lang.Throwable.class, "/error/500"));
            }
        };
    }
}

然後定義一個Controller去重寫BasicErrorController的方法

/**
 * 特別注意:這個類中的程式碼一定不能有問題,否則,你的程式可能會陷入死迴圈
 */
@Controller
@RequestMapping("/error")
@EnableConfigurationProperties({ServerProperties.class})
public class ErrorPageController implements ErrorController {
    // 這兒只貼上具體實現程式碼,關於專案原始碼會在最後附上git地址,需要的同學自行下載
    /**
     * 定義404的返回頁面
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(produces = "text/html", value = "404")
    public ModelAndView errorHtml404(HttpServletRequest request,
                                     HttpServletResponse response) {
        response.setStatus(getStatus(request).value());
        Map model = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.TEXT_HTML));
        return new ModelAndView("error/404", model);
    }

    /**
     * 定義400的返回頁面
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(produces = "text/html", value = "400")
    public ModelAndView errorHtml400(HttpServletRequest request,
                                     HttpServletResponse response) {
        response.setStatus(getStatus(request).value());
        Map model = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.TEXT_HTML));
        return new ModelAndView("error/400", model);
    }

    /**
     * 定義500的返回頁面
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(produces = "text/html", value = "500")
    public ModelAndView errorHtml500(HttpServletRequest request,
                                     HttpServletResponse response) {
        response.setStatus(getStatus(request).value());
        Map model = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.TEXT_HTML));
        return new ModelAndView("error/500", model);
    }
    // 這兒只貼上具體實現程式碼,關於專案原始碼會在最後附上git地址,需要的同學自行下載
}

然後新建三個頁面,同時頁面中分別標註一下具體的異常型別,如下圖
圖片描述
此時看下專案結構
圖片描述

OK,測試訪問效果
圖片描述

這就實現了異常頁面的分離,以便於定製各個異常頁面資訊。

我可以對一個人無限的好,前提是值得。 ——慕冬雪

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4548/viewspace-2798490/,如需轉載,請註明出處,否則將追究法律責任。

相關文章