1. 程式人生 > >用Spring MVC實現自定義404頁面

用Spring MVC實現自定義404頁面

如何定義404

404,說白了就是找不到頁面,那麼如何定義“找不到”呢?

我們可以通過原始碼來看看Spring MVC如何定義“404”的:

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest, false);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}

getHandler是根據請求的url,通過handlerMapping來匹配到Controller的過程。

如果匹配不到,那麼就執行noHandlerFound方法。這個方法很簡單,返回一個404的錯誤程式碼。

我們的Web容器,比如tomcat,會根據這個錯誤程式碼來生成一個錯誤介面給使用者。

那麼,我們如何自定義這個介面呢?

重寫noHandlerFound方法

最先想到的肯定是重寫noHandlerFound方法,這個方法是protected,可以重寫。

我們需要將頁面重定向到我們自定義的404介面,那麼只需要

@Override
protected void noHandlerFound(HttpServletRequest request,
HttpServletResponse response) throws
Exception { response.sendRedirect(request.getContextPath() + "/notFound"); }

這裡我們的Controller裡需要定義一個@requestMapping("/notFound")的這麼一個方法,用來返回一個404頁面

或者,這裡應該可以採用直接訪問靜態檔案的方法。

另外,也可以通過丟擲一個異常NoSuchRequestHandlingMethodException

這樣我們就實現了自定義的404頁面。那麼,還有別的方法嗎?

利用Spring MVC的最精確匹配

Spring MVC對於url的匹配採用的是一種叫做“最精確匹配的方式”,舉個例子

比如我們同時定義了“/test/a”, "/test/*",那麼若請求的url結尾為/test/a,那麼則會匹配精確的那個,也就是"/test/a"

我們是不是可以利用這個特點來找到那些找不到的頁面?

1、首先我們定義一個攔截所有url的規則@requestMapping("*"),那麼實際上不存在找不到的頁面了,也就是永遠不會進入noHandlerFound方法體內

2、後面的步驟和平時一樣,為別的請求都配置上@requestMapping

那麼請求過來,要麼進入我們精確匹配的method(也就是找的到的),要麼進入@requestMapping("*)攔截的方法體內(也就是找不到的)

那麼我們只要讓@requestMapping("*)攔截的這個方法返回一個自定義的404介面就OK了~

利用web容器提供的error-page

還記得之前提到的web容器會提供一個404的預設介面嗎?

其實我們完全可以替換成我們自己的介面,那麼看起來這種方法應該是最簡單的了。

只需要在web.xml檔案中寫上如下程式碼就可以了:

<error-page>
<error-code>404</error-code>
<location>/resource/view/404.htm</location>
</error-page>

不過值得注意的是,這裡配置的的location其實會被當成一個請求來訪問。

那麼我們的DispatcherServlet會攔截這個請求而造成無法訪問,此時的結果是使用者介面一片空白。

所以這裡的404.htm其實是一個靜態資源,我們需要用訪問靜態資源的方式去訪問。

而在我的Spring MVC裡,resource目錄下的檔案都是不會被攔截的

比較三種方式的區別

1、最方便:那肯定是第三種了,我們只需要提供一個靜態頁面即可

2、最快捷:第一種肯定最慢,因為它會發起2個請求。第二種和第三種應該差不多

3、最靈活:從靈活性上來看,第三種肯定是最缺乏的,但是其實對於404來說並不是需要經常變化的,不過也保不準可能可以允許使用者自定義404介面等,這裡一、二兩種方式則提供了靈活性。

4、通用性:第三種應該是最通用了,而一、二 兩種則要依賴Spring MVC