//错误异常响应类
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class ErrorResponse {
private int code;
private String message;
}
//基础异常类
import com.web.enums.IResponseEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class BaseException extends Exception {
private int code;
private String message;
private IResponseEnum iResponseEnum;
private Throwable cause;
private Object[] args;
public BaseException(int code , String message){
super(message);
this.code = code;
this.message = message;
}
public BaseException(IResponseEnum iResponseEnum){
this.iResponseEnum = iResponseEnum;
}
public BaseException(IResponseEnum iResponseEnum,Object[] args , String message){
this.iResponseEnum = iResponseEnum;
this.args = args;
this.message = message;
}
public BaseException(IResponseEnum iResponseEnum,Object[] args , String message,Throwable cause){
this.iResponseEnum = iResponseEnum;
this.args = args;
this.message = message;
this.cause = cause;
}
}
//异常接口类
package com.web.enums;
public interface IResponseEnum {
int getCode();
String getMessage();
}
//全局异常处理类
import com.web.enums.ArgumentResponseEnum;
import com.web.enums.CommonResponseEnum;
import com.web.enums.ServletResponseEnum;
import com.web.exceptions.BaseException;
import com.web.exceptions.BusinessException;
import com.web.messages.UnifiedMessageSource;
import com.web.response.ErrorResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
@Slf4j
@RestControllerAdvice
public class UnifiedExceptionHandler {
private static final String ENV_PROD = "prod";
@Autowired
private UnifiedMessageSource unifiedMessageSource;
@Value("${spring.profiles.active}")
private String profile;
public String getMessage(BaseException e) {
String code = "response." + e.getIResponseEnum().toString();
String message = unifiedMessageSource.getMessage(code, e.getArgs());
if (StringUtils.isBlank(message) || message.isEmpty()) {
return e.getMessage();
}
return message;
}
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public ErrorResponse handleBusinessException(BaseException e) {
log.error(e.getMessage(), e);
return new ErrorResponse(e.getIResponseEnum().getCode(), getMessage(e));
}
@ExceptionHandler({
NoHandlerFoundException.class, HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class, MissingPathVariableException.class,
MissingServletRequestParameterException.class, TypeMismatchException.class,
HttpMessageNotReadableException.class, HttpMessageNotWritableException.class,
HttpMediaTypeNotAcceptableException.class, ServletRequestBindingException.class,
ConversionNotSupportedException.class, MissingServletRequestPartException.class,
AsyncRequestTimeoutException.class
})
@ResponseBody
public ErrorResponse handleServletException(Exception e) {
log.error(e.getMessage(), e);
int code = CommonResponseEnum.SERVER_ERROR.getCode();
try {
ServletResponseEnum servletResponseEnum = ServletResponseEnum.valueOf(e.getClass().getSimpleName());
code = servletResponseEnum.getCode();
} catch (IllegalArgumentException ex) {
log.error("class [{}] not defined in enum {}", e.getClass().getName(), ServletResponseEnum.class.getName());
}
if (ENV_PROD.equals(profile)) {
// 当为生产环境, 不适合把具体的异常信息展示给用户, 比如404.
code = CommonResponseEnum.SERVER_ERROR.getCode();
BaseException baseException = new BaseException(CommonResponseEnum.SERVER_ERROR);
String message = getMessage(baseException);
return new ErrorResponse(code, message);
}
return new ErrorResponse(code, e.getMessage());
}
@ExceptionHandler(value = BindException.class)
@ResponseBody
public ErrorResponse handleBindException(BindException e){
log.error("Parameters error",e);
return wrapperBindingResponse(e.getBindingResult());
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public ErrorResponse handleValidException(MethodArgumentNotValidException e) {
log.error("data parameter validation problem {},invalid type {}",e.getMessage(),e.getClass());
return wrapperBindingResponse(e.getBindingResult());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ErrorResponse handleException(Exception e) {
log.error(e.getMessage(), e);
if (ENV_PROD.equals(profile)) {
// 当为生产环境, 不适合把具体的异常信息展示给用户, 比如数据库异常信息.
int code = CommonResponseEnum.SERVER_ERROR.getCode();
BaseException baseException = new BaseException(CommonResponseEnum.SERVER_ERROR);
String message = getMessage(baseException);
return new ErrorResponse(code, message);
}
return new ErrorResponse(CommonResponseEnum.SERVER_ERROR.getCode(), e.getMessage());
}
private ErrorResponse wrapperBindingResponse(BindingResult bindingResult) {
StringBuilder msg = new StringBuilder();
bindingResult.getFieldErrors().forEach(item->{
if (item instanceof FieldError) {
msg.append(item.getField()).append(":");
}
msg.append(item.getDefaultMessage() == null ? "" : item.getDefaultMessage());
msg.append(";");
});
return new ErrorResponse(ArgumentResponseEnum.VALID_ERROR.getCode(), msg.toString().substring(0,msg.length()-1));
}
}