Spring Boot 全局异常/通用返回/错误代码设计

教程分享 > Java教程 > Spring (110) 2024-08-27 17:15:23

前言

spring boot 项目常用的几个类设计,方便快速搭建项目错误处理模块。

代码片段

 

错误枚举定义

@Getter
public enum ErrorCodeEnums {
//常见错误
success(200,"success"),
paramsError(400,"参数格式或类型错误"),
unAuthentication(401,"未登录或登录超时"),
unAuthorization(403,"未授权访问"),
notFound(404,"未找到访问资源"),
methodNotAllowed(405,"不允许的方法"),
internalError(500,"系统内部错误"),
//业务错误,定义前端错误4xxx,后端错误 5xxx
businessError(4000,"业务处理通用错误"),
loginError(4001,"用户名或密码错误"),
accountDisabled(4002,"账号已被禁用"),
;

final Integer code;
final String message;
ErrorCodeEnums(Integer code, String message) {
this.code = code;
this.message = message;
}
}

HTTP 状态码统一返回200,然后通过code码来区分错误。国内行情大多数达不到RESTful规范标准,所以退而求其次吧。

 

通用返回数据对象定义

@Data
@Builder
public class Result<T> implements Serializable {

/**
* 状态码
*/
int code;
/**
* 成功响应数据
*/
T data;
/**
* 错误内容
*/
String message;


/**
* 成功返回数据
* @param data 数据对象
* @return Result封装
* @param <T> 数据类型
*/
public static <T> Result<T> success(T data){
return Result.<T>builder().code(200).message("success").data(data).build();
}

/**
* 无数据返回成功
* @return Result
* @param <T> 数据类型/NULL
*/
public static <T> Result<T> success(){
return Result.success(null);
}


/**
* 失败返回
* @param enums ErrorCodeEnums
* @return Result
* @param <T> 数据类型/Void
*/
public static <T> Result<T> fail(ErrorCodeEnums enums){
return Result.<T>builder().code(enums.getCode()).message(enums.getMessage()).build();
}

/**
* 失败返回
* @param enums ErrorCodeEnums
* @return Result
* @param <T> 数据类型/Void
* @param message 追加详细描述
*/
public static <T> Result<T> fail(ErrorCodeEnums enums,String message){
if (StrUtil.isNotEmpty(message)){
return Result.<T>builder().code(enums.getCode()).message(enums.getMessage()+"-"+message).build();
}else {
return Result.<T>builder().code(enums.getCode()).message(enums.getMessage()).build();
}
}
}

自定义业务异常

@EqualsAndHashCode(callSuper = true)
@Data
public class BusinessException extends RuntimeException{
ErrorCodeEnums errorCode = ErrorCodeEnums.businessError;
public BusinessException(ErrorCodeEnums errorCode) {
this.errorCode = errorCode;
}

public BusinessException(ErrorCodeEnums errorCode, String message) {
super(message);
this.errorCode = errorCode;
}

public BusinessException() {
}

public BusinessException(String message) {
super(message);
}

public BusinessException(String message, Throwable cause) {
super(message, cause);
}

public BusinessException(Throwable cause) {
super(cause);
}

public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

业务异常配合ErrorCodeEnums枚举使用,全局错误码靠枚举统一维护。

 

全局异常拦截处理

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler({BindException.class,MethodArgumentNotValidException.class})
public Object methodArgumentNotValidException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
List<FieldError> fieldErrors= new ArrayList<>();
if (e instanceof BindException){
fieldErrors=((BindException) e).getFieldErrors();
}
List<String> errorMsg = new ArrayList<>();
for (FieldError error : fieldErrors) {
errorMsg.add("["+error.getField()+"]"+error.getDefaultMessage());
}
String errMsg = String.join(",", errorMsg);
log.error("请求地址:{},参数校验错误 :{}",request.getRequestURI(),errMsg);
return handlerView(Result.fail(ErrorCodeEnums.paramsError, errMsg),request,response);
}


@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public Object MethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("请求地址:{},参数格式或类型错误:{}",request.getRequestURI(),e.getMessage(),e);
return handlerView(Result.fail(ErrorCodeEnums.paramsError,"参数格式或类型错误"),request,response);
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public Object httpMessageNotReadableException(HttpMessageNotReadableException e,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("请求地址:{},参数格式错误:{}",request.getRequestURI(),e.getMessage());
return handlerView(Result.fail(ErrorCodeEnums.paramsError),request,response);
}

@ExceptionHandler(MissingServletRequestParameterException.class)
public Object missingServletRequestParameterException(MissingServletRequestParameterException e,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("请求地址:{},参数缺失:{}",request.getRequestURI(),e.getParameterName());
return handlerView(Result.fail(ErrorCodeEnums.paramsError,e.getParameterName()),request,response);
}


@ExceptionHandler(ConstraintViolationException.class)
public Object constraintViolationException(ConstraintViolationException e,HttpServletRequest request,HttpServletResponse response)throws IOException{
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
List<String> messageList=new ArrayList<>();
for (ConstraintViolation<?> next : constraintViolations) {
messageList.add(next.getMessage());
}
log.error("请求地址:{},参数缺失-:{}",request.getRequestURI(),String.join(",",messageList));
return handlerView(Result.fail(ErrorCodeEnums.paramsError,String.join(",",messageList)),request,response);
}

@ExceptionHandler({AuthenticationException.class})
public Object authenticationException(AuthenticationException authenticationException,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("请求地址:{},未登录或令牌无效:{}",request.getRequestURI(),authenticationException.getMessage(),authenticationException);
return handlerView(Result.fail(ErrorCodeEnums.unAuthentication,authenticationException.getMessage()),request,response);
}

@ExceptionHandler({AccessDeniedException.class})
public Object accessDeniedException(AccessDeniedException e,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("请求地址:{},未授权访问:{}",request.getRequestURI(),e.getMessage(),e);
return handlerView(Result.fail(ErrorCodeEnums.unAuthorization),request,response);
}



@ExceptionHandler(BusinessException.class)
public Object businessException(BusinessException ex,HttpServletRequest request,HttpServletResponse response) throws IOException {
StackTraceElement traceElement = ex.getStackTrace()[0];
String message;
if (Objects.nonNull(ex.getCause())){
message=ex.getCause().getMessage();
}else{
if (StrUtil.isNotBlank(ex.getMessage())){
message=ex.getMessage();
}else{
message="无错误内容显示或空指针";
}
}
log.error("[BusinessException] {} \n 报错定位:{}",message,traceElement.getClassName()+"."+traceElement.getMethodName()+": 行数:"+traceElement.getLineNumber());
return handlerView(Result.fail(ex.getErrorCode(),ex.getMessage()),request,response);
}


@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Object httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e,HttpServletRequest request,HttpServletResponse response) throws IOException {
String method = e.getMethod();
String uri = request.getRequestURI();
log.error("请求地址:{},method:{} 方法不支持",uri,method);
return handlerView(Result.fail(ErrorCodeEnums.methodNotAllowed),request,response);

}

@ExceptionHandler(NoResourceFoundException.class)
public Object exception(NoResourceFoundException e, HttpServletRequest request, HttpServletResponse response) throws IOException {
log.error("Handler-->"+e.getMessage(), e);
return handlerView(Result.fail(ErrorCodeEnums.notFound),request,response);
}

@ExceptionHandler(Exception.class)
public Object exception(Exception e,HttpServletRequest request,HttpServletResponse response) throws IOException {
log.error("Handler-->"+e.getMessage(), e);
return handlerView(Result.fail(ErrorCodeEnums.internalError),request,response);
}


public Object handlerView(Result<?> result, HttpServletRequest request, HttpServletResponse response) throws IOException {
if (isApi(request)){
response.addHeader("Content-Type","application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(result));
return null;
}else{
return result;
}
}


public static boolean isApi(HttpServletRequest request) {
//请求头判断
String header = request.getHeader("X-Request-With");
if ("XMLHttpRequest".equalsIgnoreCase(header)) {
return true;
}
//路径判断
String requestURI = request.getRequestURI();
return requestURI.startsWith("/api/");
}

}

提示:如果仅有接口则直接使用@RestControllerAdvice注解

 

URI设计规范备份

 

VIP资源,登录后查阅

此处内容已经隐藏,需要开通会员后刷新查阅

登录/注册

 

 

 

 

https://www.leftso.com/article/2408271229249672.html

相关文章
Spring Boot Enums枚举参数传递
前言spring boot 项目常用的几个类设计,方便快速搭建项目错误处理模块。代码片段 错误枚举定义@Getterpublic enum ErrorCodeE
Spring Boot 2.1 新特性,已升级Spring 版本为5.1,支持servlet 4.0,支持Tomcat 9.0等等
引言    通过之前spring boot mybatis 整合的讲解: spring boot mybaties整合  (spring boot mybaties 整合 基于Java注解方式写...
Spring Boot 2.0,Spring框架的Spring Boot 中的Spring Boot Actuator变化讲解。并且了解如何在Spring Boot 2.0中使用Actuator...
spring boot 1.5整合redis实现spring的缓存框架,spring boot,redis
Spring Boot 2.0 绑定properties属性资源文件 Spring Boot 2.0 读取properties配置文件值 Spring Boot 2.0获取properties配...
spring boot入门,spring boot是一个崭新的spring框架分支项目,本文讲解其属性配置相关
spring boot是一个崭新的spring框架分支项目,本文讲解基本的数据库配置
spring boot又一个spring框架的经典项目,本文讲解spring boot入门的环境配置以及第一个项目,Spring Boot 入门教程
spring boot mybatis 整合使用讲解介绍,spring boot与MyBatis的使用讲解介绍。spring boot mybatis xml mapper方式的入门和通过一个简...
spring boot 入门之整合spring session实现session共享。一直以来Java编程中web项目中的session共享问题都是一个很难解决的问题。接下来将讲解通过sprin...
Spring Boot 2.0 Redis整合,通过spring boot 2.0整合Redis作为spring缓存框架的实现。
Spring Boot validation整合hibernate validator实现数据验证,Spring Boot validation使用说明,Spring Boot validat...
spring boot 入门之spring session实现restful apis。通过spring boot或者spring mvc整合spring session的方式来实现sessio...