#全局异常处理
最近搭建项目,对于异常进行统一包装处理,统一包装异常以json的形式进行展示,保持代码结构优雅,性能稳定,不将原生的exception展示给前端,保持约定,统一格式,做工程化代码结构。

异常处理一共包括两种,系统自动抛出异常,人为手动抛出异常。统一将异常在collection层进行捕捉,在以统一的json格式进行展示。

因为入参校验采用注解形式,将错误信息捕捉,并返回前端原因,有助于使用者理解。

##全局异常捕捉code

import java.net.ConnectException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import javax.validation.ValidationException;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;

import com.ds.face.pojo.dto.ResponseDTO;

import lombok.extern.slf4j.Slf4j;

/**
* 全局异常处理
*
* @author Simon
*
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

@ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody ResponseDTO handleNullPointerException(NullPointerException ex) {
log.info(ex.getMessage());
System.out.println(ex);
return ResponseDTO.builder().status(400).message("ERROR_BAD_PARAM").body(ex.getMessage()).build();
}

@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody ResponseDTO handleIllegalArgumentException(ValidationException ex) {
log.error("参数绑定失败", ex);
return ResponseDTO.builder().status(400).message("ERROR_BAD_PARAM").body(ex.getMessage()).build();
}

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ResponseDTO handleException(final MethodArgumentNotValidException ex) {
log.error("参数绑定失败", ex);
return this.handleException(new BindException(ex.getBindingResult()));
}

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody ResponseDTO handleIllegalArgumentException(IllegalArgumentException ex) {
log.error("类型转化错误", ex);
return ResponseDTO.builder().status(400).message("ERROR_TYPE_CONVERSION").body(ex.getMessage()).build();
}

@ExceptionHandler(ControlledException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody ResponseDTO handleControlledException(ControlledException ex) {
log.error("可控制错误", ex);
return ResponseDTO.builder().status(ex.getErrorCode()).message(ex.getMessage()).body(ex.getContent()).build();
}

@ExceptionHandler(HttpConnectionException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody ResponseDTO handleHttpConnectionException(HttpConnectionException ex) {
log.error("访问上游系统失败", ex);
return ResponseDTO.builder().status(500).message("ERROR_RESPONSE").body(ex.getMessage()).build();
}

@ExceptionHandler(HttpServerErrorException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody ResponseDTO handleHttpServerErrorException(HttpServerErrorException ex) {
log.error("访问上游系统失败", ex);
return ResponseDTO.builder().status(500).message("ERROR_CONNECTION_FAIL")
.body("The parent system connection refused").build();
}

@ExceptionHandler(HttpClientErrorException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody ResponseDTO handleHttpServerErrorException(HttpClientErrorException ex) {
log.error("访问上游系统失败", ex);
return ResponseDTO.builder().status(500).message("ERROR_CONNECTION_FAIL")
.body("The parent system connection refused").build();
}

@ExceptionHandler(ConnectException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody ResponseDTO handleConnectException(ConnectException ex) {
log.error("访问上游系统失败", ex);
return ResponseDTO.builder().status(500).message("ERROR_CONNECTION_FAIL")
.body("The parent system connection refused").build();
}

@ExceptionHandler(SocketException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public @ResponseBody ResponseDTO handleSocketException(SocketException ex) {
log.error("连接异常", ex);
return ResponseDTO.builder().status(500).message("ERROR_CONNECTION_FAIL")
.body("The parent system connection refused").build();
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
@ResponseBody
public ResponseDTO handleException(final BindException ex) {
log.error("参数绑定失败", ex);
List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
List<ObjectError> globalErrors = ex.getBindingResult().getGlobalErrors();
List<String> errors = new ArrayList<>(fieldErrors.size() + globalErrors.size());
for (FieldError fieldError : fieldErrors) {
String error = fieldError.getDefaultMessage();
if (error.contains("NumberFormatException")) {
error = fieldError.getField() + ":请输入正确的数字!";
}
if (error.contains("ConversionFailedException") && error.contains("annotation.DateTimeFormat")) {
StringBuilder buff = new StringBuilder(fieldError.getField());
buff.append("时间格式不合法!");
error = buff.toString();
}
errors.add(error);
}

for (ObjectError objectError : globalErrors) {
String error = objectError.getDefaultMessage();
errors.add(error);
}
return ResponseDTO.builder().status(400).message("ERROR_BAD_PARAM").body(StringUtils.join(errors, " | "))
.build();
}

@ExceptionHandler(SuccessResponse.class)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody ResponseDTO handleSuccessResponse(SuccessResponse ex) {
log.error("成功返回上游问题", ex);
return ResponseDTO.builder().status(ex.getErrorCode()).message(ex.getMessage()).body(ex.getContent()).build();
}
}

##自定义异常

/**
* 其定义空异常
*
* @author Somin
* @date 2018年7月05日
*/
public class ControlledException extends RuntimeException {
private static final long serialVersionUID = 1L;

public ControlledException(Integer errorCode, String message, String content) {
super();
this.errorCode = errorCode;
this.message = message;
this.content = content;
}
private Integer errorCode;
private String message;
private String content;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public Integer getErrorCode() {
return errorCode;
}

public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
}

##自定义成功返回值

public class SuccessResponse extends RuntimeException {
private static final long serialVersionUID = 1L;

public SuccessResponse(Integer errorCode, String message, String content) {
super();
this.errorCode = errorCode;
this.message = message;
this.content = content;
}

private Integer errorCode;
private String message;
private String content;

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public Integer getErrorCode() {
return errorCode;
}

public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
}