29.Spring Boot中異常處理與REST格式處理

團長李雲龍發表於2019-04-03

我在專案中是想做純粹的前後端分離的,所有資料都通過介面來返回,那麼在這個過程勢必需要解決兩個問題,一是對異常的處理還有一個就是當出現404這樣的錯誤的時候我也需要把這個異常封裝成json的格式給到前端,我在網上找的一個部落格見連結在專案中使用SpringMVC全域性異常處理,這篇文章其實已經能很好的處理一些自定義的異常與系統出現的一些404等異常,但是還是有點不大夠的,主要是在返回的json格式上,當出現404的時候其實這個時候我們也還是想有一個data這樣的欄位在其中,只不過是在返回的欄位中succes是false或者是為1這樣的一個欄位,也就是如下所示 異常資料的格式

異常404的格式
正常資料的格式
返回正常資料的格式
那麼在前一篇文章中那樣我感覺還是不大夠的需要進行補充一下

1.修改ErrorDTO

把原部落格中的ErrorDTO修改成JsonDTO需要做的就是在JsonDTO中增加一個success跟data屬性,那麼在每個介面中我返回資料的時候我就返回這個JsonDTO回去

package com.gz.whblog.utils;

public class JsonDTO {
    
    private boolean success;
    private int msgcode;
    private String msg;
    private Object data;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public int getMsgcode() {
        return msgcode;
    }

    public void setMsgcode(int msgcode) {
        this.msgcode = msgcode;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public JsonDTO(){

    }

    public JsonDTO(boolean success,int msgcode,String msg,Object data){
        super();
        this.success = success;
        this.msgcode = msgcode;
        this.msg = msg;
        this.data = data;
    }

}
複製程式碼

請注意這裡的data是使用object來修飾的,我不管你增刪改查返回的資料是ArrayList還是字典還是什麼東西我都能給你存

2.CustomRestExceptionHandler的改寫

package com.gz.whblog.utils;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.ArrayList;

/**
* @description: 用來監聽處理全域性異常
*
* @return: 
**/

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

//    處理自定義異常
    @ExceptionHandler(CustomException.class)
    public ResponseEntity<Object> handleCustomerException(CustomException ex){
        final JsonDTO customeJsonDTD = new JsonDTO(false,ex.getMsgCode(),ex.getLocalizedMessage(),new ArrayList<>());
        return new ResponseEntity<Object>(customeJsonDTD,new HttpHeaders(),ex.getHttpStatus());
    }

//    處理通用異常,這裡舉例說明如何覆蓋處理 請求方法不支援的異類
    @Override
    protected  ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        final JsonDTO customeJsonDTD = new JsonDTO(false,status.value(),"httpRequestMethodNotSupported",new ArrayList<>());
        System.out.println("我是全域性處理請求方法不支援方法");
        return new ResponseEntity<Object>(customeJsonDTD,new HttpHeaders(),status);
    }

//    重寫系統的404方法
    @Override
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        final JsonDTO customeJsonDTD = new JsonDTO(false,status.value(),"NoHandlerFoundException",new ArrayList<>());
        System.out.println("我是全域性處理404異常方法");
        return new ResponseEntity<Object>(customeJsonDTD,new HttpHeaders(),status);
    }
}
複製程式碼

在自定義異常的方法中,如果遇到異常在data部分返回data部分就是一個空的list,當然這裡返回的data也可以你去寫null,但是我認為在這個地方寫一個返回的空陣列更好

  • 1.是你在呼叫自定義異常的時候也可以不要去管這個data部分的值了;
  • 2.是前端拿到這個data值不要去處理為null的一些異常問題 另外在這個地方,需要注意的是這裡對系統出現的異常程式碼像,我才重寫了404跟405兩個問題,如果你要處理500的問題,那你是需要再次重寫的,你可能會說這我怎麼知道要重寫多少方法?沒關係這是很容易找到的 點選ResponseEntityExceptionHandler進去檢視原始碼
    29.Spring Boot中異常處理與REST格式處理
    這裡就是一些異常類
    29.Spring Boot中異常處理與REST格式處理
    以下就是可以重寫的一些方法
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
			HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		pageNotFoundLogger.warn(ex.getMessage());

		Set<HttpMethod> supportedMethods = ex.getSupportedHttpMethods();
		if (!CollectionUtils.isEmpty(supportedMethods)) {
			headers.setAllow(supportedMethods);
		}
		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
		protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(
			HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		List<MediaType> mediaTypes = ex.getSupportedMediaTypes();
		if (!CollectionUtils.isEmpty(mediaTypes)) {
			headers.setAccept(mediaTypes);
		}

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(
			HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}

	protected ResponseEntity<Object> handleMissingPathVariable(
			MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleMissingServletRequestParameter(
			MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleServletRequestBindingException(
			ServletRequestBindingException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleConversionNotSupported(
			ConversionNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleTypeMismatch(
			TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleHttpMessageNotReadable(
			HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleHttpMessageNotWritable(
			HttpMessageNotWritableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleMethodArgumentNotValid(
			MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleMissingServletRequestPart(
			MissingServletRequestPartException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleBindException(
			BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	protected ResponseEntity<Object> handleNoHandlerFoundException(
			NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

		return handleExceptionInternal(ex, null, headers, status, request);
	}
複製程式碼
	@Nullable
	protected ResponseEntity<Object> handleAsyncRequestTimeoutException(
			AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {

		if (webRequest instanceof ServletWebRequest) {
			ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
			HttpServletResponse response = servletWebRequest.getResponse();
			if (response != null && response.isCommitted()) {
				if (logger.isWarnEnabled()) {
					logger.warn("Async request timed out");
				}
				return null;
			}
		}

		return handleExceptionInternal(ex, null, headers, status, webRequest);
	}
複製程式碼
	protected ResponseEntity<Object> handleExceptionInternal(
			Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {

		if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
			request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
		}
		return new ResponseEntity<>(body, headers, status);
	}
複製程式碼

至於覺得過多嫌麻煩的話,我也不知道別人高手是怎麼處理的,我目前的一些方法就是挨個這樣重寫了

3.自定義異常CustomException

package com.gz.whblog.utils;

import org.springframework.http.HttpStatus;

/**
* @description: 自定義異常類
*
* @return: 
**/
public class CustomException extends RuntimeException {

    private HttpStatus httpStatus;

    private int msgCode;
    public CustomException(HttpStatus httpStatus,int msgCode,String message){
        super(message);
        this.httpStatus = httpStatus;
        this.msgCode = msgCode;
    }

    public CustomException(String message,int errorCode,Exception e){
        super(message,e.getCause());
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    public void setHttpStatus(HttpStatus httpStatus) {
        this.httpStatus = httpStatus;
    }

    public int getMsgCode() {
        return msgCode;
    }

    public void setMsgCode(int msgCode) {
        this.msgCode = msgCode;
    }
    
}
複製程式碼

4.異常狀態碼列舉類ExceptionEnum

package com.gz.whblog.utils;

import org.springframework.http.HttpStatus;

/**
* @description: 異常列舉類
*
* @return: 
**/
public enum  ExceptionEnum {

//    跟資料庫CRUD有關的一些自定義程式碼
    ADD_DATA_SUCCESS(20000,"操作成功",HttpStatus.OK),
    QUERARY_DATA_SUCCESS(20001,"查詢成功",HttpStatus.OK),
    INSERT_DATA_SUCCESS(20002,"插入成功",HttpStatus.OK),
    UPDATE_DATA_SUCCESS(20003,"更新資料成功",HttpStatus.OK),
    DELETE_DATA_SUCCESS(20004,"刪除資料成功",HttpStatus.OK),

//    使用者登入有關的一些自定義程式碼
    LOGIN_USER_SUCCESS(10000,"登入成功",HttpStatus.OK),
    LOGIN_USERNAME_ERROR(10001,"使用者名稱錯誤",HttpStatus.BAD_REQUEST),
    LOGIN_PASSWORD_ERROR(10002,"登入密碼錯誤",HttpStatus.BAD_REQUEST),
    LOGIN_VERIFICODE_ERROR(10003,"驗證碼錯誤",HttpStatus.BAD_REQUEST),
    LOGIN_TELEPHONE_ERROR(10004,"手機號錯誤",HttpStatus.BAD_REQUEST),

    ;

    private int msgcode;
    private String msgdesc;
    private HttpStatus httpStatus;


    ExceptionEnum(int msgcode, String msgdesc, HttpStatus status) {
        this.msgcode = msgcode;
        this.msgdesc = msgdesc;
        this.httpStatus = status;
    }

    public int getMsgcode() {
        return msgcode;
    }

    public void setMsgcode(int msgcode) {
        this.msgcode = msgcode;
    }

    public String getMsgdesc() {
        return msgdesc;
    }

    public void setMsgdesc(String msgdesc) {
        this.msgdesc = msgdesc;
    }

    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    public void setHttpStatus(HttpStatus httpStatus) {
        this.httpStatus = httpStatus;
    }
}
複製程式碼

如果有其他的一些操作還可以繼續新增一些狀態碼的 Github同步更新個人學習筆記,如果這篇文章對你有好處點個星星你不虧 WiHongNoteBook

相關文章