如何定義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