首页>>后端>>SpringBoot->Spring Boot统一接口返回和全局异常处理

Spring Boot统一接口返回和全局异常处理

时间:2023-11-29 本站 点击:0

背景

在分布式、微服务盛行的今天,绝大部分项目都采用的微服务框架,前后端分离方式。前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端。维护一套完善且规范的接口是非常有必要的, 这样不仅能够提高对接效率,也可以让我的代码看起来更加简洁优雅。

使用统一返回结果时,还有一种情况,就是程序的报错是由于运行时异常导致的结果,有些异常是我们在业务中抛出的,有些是无法提前预知。

因此,我们需要定义一个统一的全局异常,在Controller捕获所有异常,并且做适当处理,并作为一种结果返回。

统一接口返回

定义API返回码枚举类

publicenumResultCode{/*成功状态码*/SUCCESS(200,"成功"),/*错误状态码*/NOT_FOUND(404,"请求的资源不存在"),INTERNAL_ERROR(500,"服务器内部错误"),PARAMETER_EXCEPTION(501,"请求参数校验异常"),/*业务状态码*/USER_NOT_EXIST_ERROR(10001,"用户不存在"),;privateIntegercode;privateStringmessage;publicIntegercode(){returnthis.code;}publicStringmessage(){returnthis.message;}ResultCode(Integercode,Stringmessage){this.code=code;this.message=message;}}

定义正常响应的API统一返回体

@DatapublicclassResult<T>implementsSerializable{privateIntegercode;privateStringmessage;privatebooleansuccess=true;privateTdata;@JsonIgnoreprivateResultCoderesultCode;privateResult(){}publicvoidsetResultCode(ResultCoderesultCode){this.resultCode=resultCode;this.code=resultCode.code();this.message=resultCode.message();}publicResult(ResultCoderesultCode,Tdata){this.code=resultCode.code();this.message=resultCode.message();this.data=data;}publicstatic<T>Result<T>success(){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);returnresult;}publicstatic<T>Result<T>success(Tdata){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);result.setData(data);returnresult;}}

定义异常响应的API统一返回体

@DatapublicclassErrorResultimplementsSerializable{privateIntegercode;privateStringmessage;privatebooleansuccess=false;@JsonIgnoreprivateResultCoderesultCode;publicstaticErrorResulterror(){ErrorResultresult=newErrorResult();result.setResultCode(ResultCode.INTERNAL_ERROR);returnresult;}publicstaticErrorResulterror(Stringmessage){ErrorResultresult=newErrorResult();result.setCode(ResultCode.INTERNAL_ERROR.code());result.setMessage(message);returnresult;}publicstaticErrorResulterror(Integercode,Stringmessage){ErrorResultresult=newErrorResult();result.setCode(code);result.setMessage(message);returnresult;}publicstaticErrorResulterror(ResultCoderesultCode,Stringmessage){ErrorResultresult=newErrorResult();result.setResultCode(resultCode);result.setMessage(message)returnresult;}}

编写包装返回结果的自定义注解

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD})//作用于方法和类(接口)上@Documentedpublic@interfaceResponseResult{}

定义返回结果拦截器

@ComponentpublicclassResponseResultInterceptorimplementsHandlerInterceptor{/*使用统一返回体的标识*/privatestaticfinalStringRESPONSE_RESULT_ANNOTATION="RESPONSE-RESULT-ANNOTATION";@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){//正在处理请求的方法beanif(handlerinstanceofHandlerMethod){finalHandlerMethodhandlerMethod=(HandlerMethod)handler;//获取当前类finalClass<?>clazz=handlerMethod.getBeanType();//获取当前方法finalMethodmethod=handlerMethod.getMethod();//判断是否在类对象上加了注解if(clazz.isAnnotationPresent(ResponseResult.class)){//设置该请求返回体,需要包装,往下传递,在ResponseBodyAdvice接口进行判断request.setAttribute(RESPONSE_RESULT_ANNOTATION,clazz.getAnnotation(ResponseResult.class));}//判断是否在方法上加了注解elseif(method.isAnnotationPresent(ResponseResult.class)){//设置该请求返回体,需要包装,往下传递,在ResponseBodyAdvice接口进行判断request.setAttribute(RESPONSE_RESULT_ANNOTATION,method.getAnnotation(ResponseResult.class));}}returntrue;}}

WebMvc配置类拦截器注册者添加返回结果拦截器

@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{/***添加自定义拦截器*/@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newResponseResultInterceptor()).addPathPatterns("/**");}}

编写响应体处理器

/***统一处理响应体,用Result.success静态方法包装,*在API接口使用时就可以直接返回原始类型*/@RestControllerAdvicepublicclassResponseResultHandlerimplementsResponseBodyAdvice<Object>{/*使用统一返回体的标识*/privatestaticfinalStringRESPONSE_RESULT_ANNOTATION="RESPONSE-RESULT-ANNOTATION";@Overridepublicbooleansupports(MethodParametermethodParameter,Class<?extendsHttpMessageConverter<?>>aClass){ServletRequestAttributessra=(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequest=Objects.requireNonNull(sra).getRequest();ResponseResultresponseResult=(ResponseResult)request.getAttribute(RESPONSE_RESULT_ANNOTATION);//判断返回体是否需要处理returnresponseResult!=null;}@OverridepublicObjectbeforeBodyWrite(Objectbody,MethodParametermethodParameter,MediaTypemediaType,Class<?extendsHttpMessageConverter<?>>aClass,ServerHttpRequestserverHttpRequest,ServerHttpResponseserverHttpResponse){//异常响应体则直接返回code+message的消息体if(bodyinstanceofErrorResult){returnbody;}//正常响应体则返回Result包装的code+message+data的消息体returnResult.success(body);}}

接口调用

@Api("用户管理")@RestController@RequestMapping("user")@ResponseResult//作用于类上,对所有接口有效publicclassUserController{@AutowiredprivateUserServiceuserService;@ResponseResult//作用于方法上@ApiOperation("根据ID查询用户")@GetMapping("one")publicUserselectOne(Longid){//由于在ResponseResultHandler中已经统一将返回数据用Result.success包装了,//直接返回原始类型即可,代码更简洁returnthis.userService.queryById(id);}@ResponseResult@ApiOperation("查询所有用户")@GetMapping("all")publicList<User>selectAll(Pagepage){//由于在ResponseResultHandler中已经统一将返回数据用Result.success包装了,//直接返回原始类型即可,代码更简洁returnthis.userService.queryAllByLimit(page);}}

测试结果

全局异常处理

编写自定义异常基类

@DatapublicclassBaseExceptionextendsRuntimeException{privatestaticfinalintBASE_EXCEPTION_CODE=ResultCode.INTERNAL_ERROR.code();privatestaticfinalStringBASE_EXCEPTION_MESSAGE=ResultCode.INTERNAL_ERROR.message();privateIntegercode;privateStringmessage;publicBaseException(){super(BASE_EXCEPTION_MESSAGE);this.code=BASE_EXCEPTION_CODE;this.message=BASE_EXCEPTION_MESSAGE;}publicBaseException(Stringmessage){super(message);this.code=BASE_EXCEPTION_CODE;this.message=message;}publicBaseException(ResultCoderesultCode){super(resultCode.message());this.code=resultCode.code();this.message=resultCode.message();}publicBaseException(Throwablecause){super(cause);this.code=BASE_EXCEPTION_CODE;this.message=BASE_EXCEPTION_MESSAGE;}publicBaseException(Stringmessage,Throwablecause){super(message,cause);this.code=BASE_EXCEPTION_CODE;this.message=message;}publicBaseException(Integercode,Stringmessage){super(message);this.code=code;this.message=message;}publicBaseException(Integercode,Stringmessage,Throwablecause){super(message,cause);this.code=code;this.message=message;}}

编写自定义业务异常类

publicclassBizExceptionextendsBaseException{publicBizException(ResultCoderesultCode){super(resultCode);}}

定义全局异常处理类

通过@ExceptionHandler注解来统一处理某一类异常

@DatapublicclassResult<T>implementsSerializable{privateIntegercode;privateStringmessage;privatebooleansuccess=true;privateTdata;@JsonIgnoreprivateResultCoderesultCode;privateResult(){}publicvoidsetResultCode(ResultCoderesultCode){this.resultCode=resultCode;this.code=resultCode.code();this.message=resultCode.message();}publicResult(ResultCoderesultCode,Tdata){this.code=resultCode.code();this.message=resultCode.message();this.data=data;}publicstatic<T>Result<T>success(){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);returnresult;}publicstatic<T>Result<T>success(Tdata){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);result.setData(data);returnresult;}}0

接口调用

@DatapublicclassResult<T>implementsSerializable{privateIntegercode;privateStringmessage;privatebooleansuccess=true;privateTdata;@JsonIgnoreprivateResultCoderesultCode;privateResult(){}publicvoidsetResultCode(ResultCoderesultCode){this.resultCode=resultCode;this.code=resultCode.code();this.message=resultCode.message();}publicResult(ResultCoderesultCode,Tdata){this.code=resultCode.code();this.message=resultCode.message();this.data=data;}publicstatic<T>Result<T>success(){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);returnresult;}publicstatic<T>Result<T>success(Tdata){Result<T>result=newResult<>();result.setResultCode(ResultCode.SUCCESS);result.setData(data);returnresult;}}1

测试结果

作者:l拉不拉米


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/SpringBoot/346.html