1. 程式人生 > >CheckedException和unCheckedException理解及Spring 統一異常處理和封裝

CheckedException和unCheckedException理解及Spring 統一異常處理和封裝

一、CheckedException和UnCheckedException

1.CheckedException已檢查異常

CheckedException繼承自Exception,程式內部無法控制,必須做處理,要麼使用try-atch塊捕獲,要麼throws拋給上一層。

2.UnCheckedException未檢查異常

UnCheckedException繼承自RuntimeException,一般是程式的邏輯問題引起的異常,不需要捕獲,也不需要處理。比如空指標異常等

3.demo演示:

3.1首先自定義一個Checked異常類

/**
 * @author 旺仔牛奶
 * 自定義異常類
 * 2018年1月25日 下午4:41:46
 */
public class MyCheckedException extends Exception {  
  
  private static final long serialVersionUID = 1L;
  
  private Throwable cause;

  public MyCheckedException(String exceptionMessage, Throwable cause) {  
      super(exceptionMessage, cause);  
  }  
}  

寫一個方法處理異常

//處理異常  
public void textException(String message) {
    message = "";
    try {
      String exceptionMessage = readMessage(message);
    } catch (MyCheckedException e) {
      e.printStackTrace();
    }
  }
//丟擲異常
  public String readMessage(String message) throws MyCheckedException{
    if (message == "") {
      throw new MyCheckedException("message資訊為空啦!",null);
    }
    return message;
  }

以上的例子就是一個簡單的checked異常的demo,方法readMessage是一個會丟擲checked異常的方法,TextException方法呼叫readMessage方法,有兩種選擇,一種是向上丟擲,即在TextException方法聲明後新增throws MyChekedException;(但最終還是要在最外層對異常做處理的)另外一種是在當前方法中對異常做處理,如上面的例子。

對於unchecked異常,只需要將自定義異常繼承的類修改為RuntimeException類。自定義異常類MyChekedException就變成了unchecked。例子如下:

/**
 * @author 旺仔牛奶
 * 自定義異常類
 * 2018年1月25日 下午4:41:46
 */
public class MyCheckedException extends RuntimeException {  
  
  private static final long serialVersionUID = 1L;
  
  private Throwable cause;

  public MyCheckedException(String exceptionMessage, Throwable cause) {  
      super(exceptionMessage, cause);  
  }  
}  

方法丟擲異常不需要對異常做處理(也可以去捕獲異常,只是不再是必須要做的事情)

//處理異常  
  public void textException(String message) {
    message = "";
      String exceptionMessage = readMessage(message);
  }
  
  //丟擲異常,不需要捕獲和處理異常
  public String readMessage(String message) {
    if (message == "") {
      throw new MyCheckedException("message資訊為空啦!",null);
    }
    return message;
  }

二、統一異常處理以及異常資訊的封裝

1.統一異常處理知識點介紹:

springMVC處理異常的3種方式:

(1) 使用Spring MVC提供的簡單異常處理器SimpleMappingExceptionResolver;

(2) 實現Spring的異常處理介面HandlerExceptionResolver 自定義自己的異常處理器

(3) 使用@ExceptionHandler註解實現異常處理

機制:系統的dao、service、controller出現異常都通過throws Exception向上丟擲,最後由springmvc前端控制器交由異常處理器進行異常處理。springmvc提供全域性異常處理器(一個系統只有一個異常處理器)進行統一異常處理

2.以第二種方式為例的統一異常處理的完整例項。背景:判斷字串name是否為空

首先編寫自定義異常類(這裡是unchecked異常)

public class MyTextException extends RuntimeException {

  /**
   * 自定義異常類
   */
  private static final long serialVersionUID = 1L;

  private String messageError;//錯誤資訊內容

  private String massageKey;//錯誤資訊內容對應的key。最後會把錯誤資訊存到map中

  private Throwable cause;//異常物件

  public MyTextException(String massageKey, String messageError, Throwable throwable) {

    this.massageKey = massageKey;
    this.messageError = messageError;
    this.cause = throwable;

  }

  public String getMassageKey() {
    return massageKey;
  }

  public void setMassageKey(String massageKey) {
    this.massageKey = massageKey;
  }

  public String getMessageError() {
    return messageError;
  }

  public void setMessageError(String messageError) {
    this.messageError = messageError;
  }

  public Throwable getCause() {
    return cause;
  }

  public void setCause(Throwable cause) {
    this.cause = cause;
  }

}
controller層呼叫validatorIsNull方法。該方法的用來判斷字串name是否為空白字元或者為空。以下是controller實現。
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;

@Controller
public class MyAppController {

  protected static final Logger LOG = LoggerFactory.getLogger(MyAppController.class);

  /**
   * @param name
   * @return
   */
  public MyJson validatorName() {
    String name = ""; 
    MyJson jsonObject = new MyJson();
    jsonObject.setResultString("true");
    //如果成功繼續執行,如果丟擲異常,直接在統一異常處理器中通過ModelAndView把異常資訊返回到前端
    validatorIsNull(name);
    return jsonObject;
  }

  public boolean validatorIsNull(String name) {
    boolean flag = false;
    if (StringUtils.isBlank(name)) {
      flag = true;
      throw new MyTextException("myExceptionKey", "名字為空啦啦啦啦啦", null);
    }
    return flag;
  }
}

接下來是統一異常處理部分,在這裡先採用比較常用的第二種方式做統一異常處理,我們需要把異常資訊封裝起來傳遞到前端,構造json物件。,通過ModelAndView傳遞到前端。思路如下:

a.構造json物件用來封裝異常資訊

b.定義異常處理器對異常進行處理,並把異常資訊封裝到ModelAndView返回到前端

import java.util.HashMap;
import java.util.Map;

/**
 * 封裝異常錯誤資訊的類
 * 
 * @author 旺仔牛奶  2018年1月25日 下午5:58:18
 */
public class MyJson {

  // 儲存資料結果的map
  protected Map<String, Object> message = new HashMap<String, Object>();

  // 是否執行成功標誌,如果成功success的值為true
  protected String resultString;

  // 構造方法
  public MyJson(String errorKey, String errorInfo) {
    message.put(errorKey, errorInfo);
  }

  public MyJson() {  }
  
  public Map<String, Object> getMessage() {
    return message;
  }

  public void setMessage(Map<String, Object> message) {
    this.message = message;
  }

  public String getResultString() {
    return resultString;
  }

  public void setResultString(String resultString) {
    this.resultString = resultString;
  }
}
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

/**
 * 統一異常處理器
 * 
 * @author 旺仔牛奶 2018年1月25日 下午7:46:44
 */
@Service
public class MyExceptionHandler implements HandlerExceptionResolver {
  protected static final Logger LOG = LoggerFactory.getLogger(MyExceptionHandler.class);

  // appliContext物件
  protected ApplicationContext context;

  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
      Object o, Exception e) {
    LOG.error("這裡會在控制檯列印異常資訊", e);
    if (e instanceof MyTextException) {
      return paramErrorMessage(((MyTextException) e).getMassageKey(),
          ((MyTextException) e).getMessageError());
    }
    return null;
  }

  public ModelAndView paramErrorMessage(String massageKey, String messageError) {

    MyJson jsonObject = new MyJson(massageKey, messageError);
    jsonObject.setResultString("false");
    return JsonObjectToModelView(jsonObject);
  }

  // 將異常資訊封裝到ModelAndView傳給前端
  public static ModelAndView JsonObjectToModelView(MyJson json) {
    ModelAndView model = new ModelAndView(new MappingJackson2JsonView());
    // 前端用success的值來判斷是否丟擲異常(這裡省略了執行成功時的json封裝實現,成功時success的值為true)
    model.addObject("success", json.getResultString());
    model.addObject("message", json.getMessage());
    return model;
  }

}
前端呼叫:
$.ajax({
				url : 你的controller的訪問url
				type : "POST",
				data : {
					name : nameInput,
				},
				success : function(response) {
					if (response.success == "true") {
						alter("name 不為空")
					} else {
						alter(response.message.myExceptionKey)
					}
				}
			});


關於第一種方式和第三種方式的例項後期補充。

關於物件資訊的封裝,基本思路是構造一個json基類,針對成功執行結果的返回引數和異常以及錯誤返回引數分別繼承基類去實現,這裡主要是為了方便,之定義了異常資訊的封裝。