本文主要是介绍基于Spring实现自定义错误信息返回详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...
背景
Spring 提供了 @RestConChina编程trollerAdvice
用来实现 HTTP 协议的全局异常处理。在异常信息的处理上通常只返回特定的 Response 对象,如下。
@Slf4j @RestControllerAdvice public class RestExceptionResolver { @ExceptionHandler(Exception.class) public ResponseEntity<?> processException(Exception ex) { BodyBuilder builder; Response response; ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class); if (responseStatus != null) { builder = ResponseEntity.status(responseStatus.value()); response = Response.buildFailure("500", responseStatus.reason()); } else { builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR); response = Response.buildFailure("500", ex.getMessage()); } this.process(ex, response); return www.chinasem.cnbuilder.body(response); } }
作为基础框架,笔者就遇到项目A 要求返回 Response1 对象,项目B 要求返回 Response2 对象,这个时候,适配起来就很痛苦,例如下方的代码。
@Slf4j @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = false) @ToString(callSuper = true) @Data public class Response extends DTO { private static final long serialVersionUID = 1L; private boolean success; private String errCode; // 项目A 要求错误码是字符型 private String errMessage; // 项目A 要求用这个名字 private int code; // 项目B 要求错误码是整型 private String message; // 项目B 要求用这个名字 }
另外,@RestControllerAdvice
只适用于 Web 异常捕获,我们还要考虑其他组件的情况,例如 Dubbo 捕获 RPC 异常、Sentinel 组件触发限流、Spring Security 安全框架抛出认证异常。
目标
不需要修改基础框架,允许业务方自行扩展异常返回对象。
实现
将 Response
提炼为 Builder 模式,改为 ResponseBuilder.builder()
构建返回对象。
@Slf4j @RestControllerAdvice public class RestExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<?> resolveException(Exception ex) { BodyBuilder builder; Object response; ResponseStatus status = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class); if (status != null) { builder = ResponseEntity.status(status.value()); response = ResponseBuilder.builder().buildFailure("500", status.reason()); } else { builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR); response = ResponseBuilder.builder().buildFailure("500", ex.getMessage()); } this.postProcepythonss(ex); return builder.body(response); } } public interface ResponseBuilder<T> { static ResponseBuilder<?> builder() { // 尝试从业务项目获取自定义的 Spring Bean ResponseBuilder<?> builder = ApplicationContextHelper.ClPTOgetBean(ResponseBuilder.class); if (builder != null) { return builder; } // 如果业务项目没有自定义 Bean,返回默认的 Builder return DefalutResponseBuilder.getInstance(); } T buildSuccess(); <Body> T buildSuccess(Body data); T buildFailure(String errCode, String errMessage, Object... params); } public class DefalutResponseBuilder implements ResponseBuilder<Response> { private static final DefaultResponseBuilder INSTANCE = new DefaultResponseBuilder(); private DefaultResponseBuilder() {} public static DefaultResponseBuilder getInstance() { return INSTANCE; } @Override puandroidblic Response buildSuccess() { Response response = new Response(); response.setSuccess(true); return response; } @Override public <Body> Response buildSuccess(Body data) { SingleResponse<Body> response = new SingleResponse<>(); response.setSuccess(true); response.setData(data); return response; } @Override public Response buildFailure(String errCode, String errMessage, Object... params) { Response response = new Response(); response.setSuccess(false); response.setErrCode(errCode); response.setErrMessage(MessageFormatter.arrayFormat(message, placeholders).getMessage()); return response; } } @Slf4j @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = false) @ToString(callSuper = true) @Data public class Response extends DTO { private static final long serialVersionUID = 1L; private boolean success; private String errCode; private String errMessage; }
业务方觉得 Response
不能满足需求,重新定义了新对象,如下。
@Slf4j @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode(callSuper = false) @ToString(callSuper = true) @Data public class CustomResponse { private static final long serialVersionUID = 1L; private boolean success; private int code; // 要求错误码是整型 private String message; // 前端要求用这个名字 }
创建 CustomResponseBuilder
包装 CustomResponse
对象,并标记 @Component
注解,放入 Spring Bean 管理。
@Component public class CustomResponseBuilder implements ResponseBuilder<CustomResponse> { @Override public CustomResponse buildSuccess() { CustomResponse response = new CustomResponse(); response.setSuccess(true); return response; } @Override public <Body> CustomResponse buildSuccess(Body data) { // 略 } @Override public CustomResponse buildFailure(int code, String message, Object... params) { CustomResponse response = new CustomResponse(); response.setSuccess(false); response.setCode(code); response.setMessage(MessageFormatter.arrayFormat(message, placeholders).getMessage()); return response; } }
上述已提到 ResponseBuilder.builder()
优先查找 Spring Bean,所以 CustomResponseBuilder
覆盖了框架内置的 DefaultResponseBuilder
类,全局异常捕获器返回结果时,就能返回业务方自定义的 CustomResponse
对象,这样,不需要改动框架,就能满足业务需求。
产出
根据这个思路,我们分别实现了 Web 异常、Dubbo 异常、Sentinel 限流、Security 认证等各种场景的异常处理机制,业务方只需要自行创建 ResponseBuilder
扩展自己的返回对象即可,不需要修改框架。
到此这篇关于基于Spring实现自定义错误信息返回详解的文章就介绍到这了,更多相关Spring自定义错误信息内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!
这篇关于基于Spring实现自定义错误信息返回详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!