一、前言
在开发过程中,不可避免的是需要处理各种异常,异常处理方法随处可见,所以代码中就会出现大量的'try {...} catch {...} finally {...}' 代码块,不仅会造成大量的冗余代码,而且还影响代码的可读性,所以对异常统一处理非常有必要。
二、方案说明
1)我们定义了一个统一的异常类'YamiShopBindException' 与异常管理类 'DefaultExceptionHandlerConfig'。
@Getter@b@public class YamiShopBindException extends RuntimeException{@b@@b@ /**@b@ *@b@ */@b@ private static final long serialVersionUID = -4137688758944857209L;@b@@b@ /**@b@ * http状态码@b@ */@b@ private String code;@b@@b@ private Object object;@b@@b@ private ServerResponseEntity<?> serverResponseEntity;@b@@b@ public YamiShopBindException(ResponseEnum responseEnum) {@b@ super(responseEnum.getMsg());@b@ this.code = responseEnum.value();@b@ }@b@ /**@b@ * @param responseEnum@b@ */@b@ public YamiShopBindException(ResponseEnum responseEnum, String msg) {@b@ super(msg);@b@ this.code = responseEnum.value();@b@ }@b@@b@ public YamiShopBindException(ServerResponseEntity<?> serverResponseEntity) {@b@ this.serverResponseEntity = serverResponseEntity;@b@ }@b@@b@@b@ public YamiShopBindException(String msg) {@b@ super(msg);@b@ this.code = ResponseEnum.SHOW_FAIL.value();@b@ }@b@@b@ public YamiShopBindException(String msg, Object object) {@b@ super(msg);@b@ this.code = ResponseEnum.SHOW_FAIL.value();@b@ this.object = object;@b@ }@b@@b@}
2)ResponseEnum类 - 为我们自定义的返回状态码的枚举类,定义为一个枚举类,更直观处理异常返回的状态码及异常内容,以后每增加一种异常情况,只需增加一个枚举实例即可,不用每一种异常都定义一个异常类。
public enum ResponseEnum {@b@@b@ /**@b@ * ok@b@ */@b@ OK("00000", "ok"),@b@ SHOW_FAIL("A00001", ""),@b@@b@ /**@b@ * 用于直接显示提示用户的错误,内容由输入内容决定@b@ */@b@@b@ /**@b@ * 用于直接显示提示系统的成功,内容由输入内容决定@b@ */@b@ SHOW_SUCCESS("A00002", ""),@b@@b@ /**@b@ * 未授权@b@ */@b@ UNAUTHORIZED("A00004", "Unauthorized"),@b@@b@ /**@b@ * 服务器出了点小差@b@ */@b@ EXCEPTION("A00005", "服务器出了点小差"),@b@ /**@b@ * 方法参数没有校验,内容由输入内容决定@b@ */@b@ METHOD_ARGUMENT_NOT_VALID("A00014", "方法参数没有校验");@b@@b@ private final String code;@b@@b@ private final String msg;@b@@b@ public String value() {@b@ return code;@b@ }@b@@b@ public String getMsg() {@b@ return msg;@b@ }@b@@b@ ResponseEnum(String code, String msg) {@b@ this.code = code;@b@ this.msg = msg;@b@ }@b@@b@ @Override@b@ public String toString() {@b@ return "ResponseEnum{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + "} " + super.toString();@b@ }@b@@b@}
3)'DefaultExceptionHandlerConfig'类
@Slf4j@b@@RestController@b@@RestControllerAdvice@b@public class DefaultExceptionHandlerConfig {@b@@b@ @ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })@b@ public ResponseEntity<ServerResponseEntity<List<String>>> methodArgumentNotValidExceptionHandler(Exception e) {@b@ log.error("methodArgumentNotValidExceptionHandler", e);@b@ List<FieldError> fieldErrors = null;@b@ if (e instanceof MethodArgumentNotValidException) {@b@ fieldErrors = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors();@b@ }@b@ if (e instanceof BindException) {@b@ fieldErrors = ((BindException) e).getBindingResult().getFieldErrors();@b@ }@b@ if (fieldErrors == null) {@b@ return ResponseEntity.status(HttpStatus.OK)@b@ .body(ServerResponseEntity.fail(ResponseEnum.METHOD_ARGUMENT_NOT_VALID));@b@ }@b@@b@ List<String> defaultMessages = new ArrayList<>(fieldErrors.size());@b@ for (FieldError fieldError : fieldErrors) {@b@ defaultMessages.add(fieldError.getField() + ":" + fieldError.getDefaultMessage());@b@ }@b@ return ResponseEntity.status(HttpStatus.OK)@b@ .body(ServerResponseEntity.fail(ResponseEnum.METHOD_ARGUMENT_NOT_VALID, defaultMessages));@b@ }@b@@b@ @ExceptionHandler(YamiShopBindException.class)@b@ public ResponseEntity<ServerResponseEntity<?>> unauthorizedExceptionHandler(YamiShopBindException e){@b@ log.error("mall4jExceptionHandler", e);@b@@b@ ServerResponseEntity<?> serverResponseEntity = e.getServerResponseEntity();@b@ if (serverResponseEntity!=null) {@b@ return ResponseEntity.status(HttpStatus.OK).body(serverResponseEntity);@b@ }@b@ // 失败返回消息 状态码固定为直接显示消息的状态码@b@ return ResponseEntity.status(HttpStatus.OK).body(ServerResponseEntity.fail(e.getCode(),e.getMessage()));@b@ }@b@@b@ @ExceptionHandler(Exception.class)@b@ public ResponseEntity<ServerResponseEntity<Object>> exceptionHandler(Exception e){@b@ log.error("exceptionHandler", e);@b@ return ResponseEntity.status(HttpStatus.OK).body(ServerResponseEntity.fail(ResponseEnum.EXCEPTION));@b@ }@b@}
4)前台异常处理 - 前端请求与相应做了封装,请求响应的内容会被拦截器所拦截,当后台返回给前台特定的状态码,前台将显示不同报错信息。请求响应非常常见,我们查看在'src\utils\httpRequest.js'里面的其中一段代码(这里将会统一拦截返回的状态码如'400',进行错误提示。)
'''javascript@b@http.interceptors.response.use(response => {@b@ return response@b@}, error => {@b@ switch (error.response.status) {@b@ case 400:@b@ Message.error(error.response.data)@b@ break@b@ case 401:@b@ clearLoginInfo()@b@ router.push({ name: 'login' })@b@ break@b@ case 405:@b@ Message.error('http请求方式有误')@b@ break@b@ case 500:@b@ Message.error('服务器出了点小差,请稍后再试')@b@ break@b@ case 501:@b@ Message.error('服务器不支持当前请求所需要的某个功能')@b@ break@b@ }@b@ return Promise.reject(error)@b@})@b@'''
总结 :我们的上述代码使用http状态码对请求进行统一响应,其中最大的 RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。