一,異常分類
java異常分爲"檢查"和"非檢查"兩類,"檢查"二字的意思是,代碼編譯時,編譯器會去Check一下有沒有進行異常處理(捕獲或向上拋),對於歸類爲需要檢查的異常,若沒處理,編譯就過不去。
初學時常常想exception爲啥要這樣分類處理呢? 後來才明白,異常不過兩種:主觀和客觀,一個大多數情況下可以避免,一個大多數情況下無法避免。
像NullPointerException這類異常,大多跟程序員素質掛鉤(開發好,測試好, 基本不會在系統運行後蹦出來), 基本是可以避免的,java語法當初把它們歸類爲“非檢查”,也算給程序員和編譯器省了不少事。
而像IOException這類跟外在環境有關的異常,幾乎是不可避免的(指不定哪一天哪一秒網絡就掛了),但是當不期而遇時,程序還是要有所作爲,所以編譯器有必要督促一下程序員,Check一下,看看是否對這些可能不期而至的異常進行了處理。當Exception對象傳遞到某個節點後,程序就可以執行一些必要措施了,比如:給用戶一個友好提示("系統繁忙,請重試")。
二,異常的統一處理
1,服務器處理
下面列舉Tomcat和Nginx爲例
Tomcat是Servlet容器,主要處理動態請求,在web.xml下配置,按http返回碼或Exception類型來處理:
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/views/error/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/WEB-INF/views/error/throwable.jsp</location>
</error-page>
Nginx,也可以通過Http返回碼很方便地指定異常時的返回頁面:
server {
listen 80 ;
server_name xx.com ;
root /var/www ;
index index.html ;
error_page 404 /404.html ;
location = /404.html {
root /usr/share/nginx/html;
}
}
2,應用程序框架處理
以Spring boot爲例, 在處理接口返回時, 進行全局異常的捕獲
1) 自定義業務異常
/**
* 自定義業務異常類
*/
public class BusinessException extends RuntimeException {
private String code;
public BusinessException(String code, String message) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
public String getMessage() {
return super.getMessage();
}
}
2) 定義接口返回數據結構
/**
* 接口返回數據對象
* @param <T> 業務對象
*/
public class Result<T> implements Serializable {
private String code;
private String message;
private T data;
public Result(String code,String message){
super();
this.code=code;
this.message=message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
3) 全局捕獲處理
@ControllerAdvice
public class ExceptionController {
private Logger logger= LoggerFactory.getLogger(ExceptionController.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result exceptionOut(Exception e){
logger.error("全局異常捕獲,e:{}",e);
Result result=null;
if(e instanceof BusinessException){
result= new Result(((BusinessException) e).getCode(),e.getMessage());
}else{
result= new Result("500","系統異常");
}
return result;
}
}