看到 Exception 這個單詞都心慌 如果有一天你發現好久沒有看到 這個單詞了,那你會不會想念她?我是不會的。她如女孩一樣的令人心動又心慌,又或者你已經練功到了孤獨求敗,等了半輩子終於看到了她,這時候你的小弟準備衝上去解決它說:大哥,我來解決它。你擺擺手說:還是我來最後一次吧... 從此,你再也 ...
看到 Exception 這個單詞都心慌
如果有一天你發現好久沒有看到Exception
這個單詞了,那你會不會想念她?我是不會的。她如女孩一樣的令人心動又心慌,又或者你已經練功到了孤獨求敗,等了半輩子終於看到了她,這時候你的小弟準備衝上去解決它說:大哥,我來解決它。你擺擺手說:還是我來最後一次吧...
從此,你再也沒看到過Exception
了。
異常是個好東西
做開發的對異常在熟悉不過了,幾乎是天天打交道的。記得當年寫代碼的時候記住的第一個異常是未將對象引用設置到對象的實例
,現在想想已經好久沒有看到他了,當然這是 .Net 下的一個異常,對應 Java 下的是java.lang.NullPointerException
。
其實,異常並不可怕,可怕的是你不知道怎麼解決它。 解決異常的方式有很多種,比如寫好每一行代碼,保證不出任何邏輯錯誤,就可以從根本上解決問題,但是,沒有一個程式員能保證自己的代碼不報異常,這也就是為什麼會有 Bug
這個令人討厭的東西了。當然,如果我們寫的代碼都沒有異常,不出 Bug ,那怎麼讓我們有和測試妹子在一起工作的機會呢!哈哈哈...
既然我們保證不了從根本上解決代碼不出異常的情況,那我們是誰阿,我們為了在測試妹子面前展示厲害到無敵的敲代碼能力,我們就偷偷的在業務代碼里使用 try...catch...
來讓她看不出你寫代碼能力不行,你這時候就厲害到不行了,你脈脈看著她,她看著你...
難道不應該有即使我們不使用 try...catch...
也能捕獲寫出來的異常麽?
這裡有一本《異常秘籍》
並不是說使用 try...catch...
不行,是因為在程式里可能會有你可預知的異常,這時候你當然會去使用它來捕獲異常,但是如果在一個你不可預知的方法里,你本能認為它不會出異常,你還會使用 try...catch...
去捕獲麽?如果你回答會,那我問你:你意思就是在每一個方法裡加入 try...catch...
代碼了?
當然,這樣並不是不行,是不太好。你想想,這樣寫起來是不是也太累了,我們都很懶的,而且我們程式里有一個講究是「耦合性」,那你這就完全不符合「高內聚、低耦合」咯?簡單說,異常的處理對業務代碼的侵入性太強了,不夠美,我們當然有更好的處理方式了。
我們可不可以統一處理異常呢? 當然可以啦!
現在就新建一個ExceptionHandler.java
異常處理類。
@Component
public class ExceptionHandler implements HandlerExceptionResolver {
private static Logger log = Logger.getLogger(ExceptionHandler.class);
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
log.error("ExceptionHandler 捕獲的異常:", exception);
String requestType = request.getHeader("X-Requested-With");
String type = "api"; //TODO:
if (!type.equals("api") && StrUtil.isNullOrEmpty(requestType)) {
// 非API請求
return new ModelAndView("redirect:/500.html");
} else {// JSON格式返回
Map<String, Object> responseMap = new HashMap<String, Object>();
responseMap.put("code", -1);
responseMap.put("msg", "系統異常,請稍後重試!");
String json = new Gson().toJson(responseMap);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
response.getWriter().write(json);
response.getWriter().flush();
return null;
} catch (IOException e) {
log.error("", e);
}
}
return new ModelAndView("redirect:/500.html");
}
}
好,就這樣簡單,完成了異常的統一處理。其實是 Spring 中定義的 HandlerExceptionResolver
介面,我們重寫裡邊的 resolveException
方法就可以捕獲項目中未處理的異常。當然,這就要求我們項目中的異常要一層一層的拋出去了,這時候不要擔心,我們會最終捕獲它的。
現在簡單說說上邊我的捕獲代碼的處理方式,首先,我捕獲到異常就寫一個 log 記錄它,以便於我們找出查看,然後,如果是我們的 API 介面請求的話,我就返回介面的統一 Json 格式,如果是其他請求的話,我就會返回到一個 500 的錯誤頁面,以優雅的方式提示用戶。
怎麼使用
其實,完全就不用說怎麼使用了,非常簡單的用法,mafly.那這裡我就試著拋一個異常出去,然後故意不捕獲它,看看結果到底會怎樣?
1.先在 ServiceImp 層拋一個異常。
2.在 Controller 層調用這個方法。
3.請求一個 API 介面。
這時候,你看控制台列印出來了異常日誌,就是我們剛剛拋出來的,你也可以調試一下,看看執行過程。這個時候,你就可以隨心所欲的統一處理異常了。
文章的具體的案例,都可以訪問我的 Github 看到 https://github.com/mafly/SpringDemo