• Spring boot统一错误处理


    Spring boot统一错误处理

    期望定义一种规范,能让前端非常方便地处理接口错误。那么问题来了,前端怎么处理接口比较方便呢?

    前端脚手架通常会为所有的API请求写一个拦截器,其中拦截器很重要的一个能力就是对数据进行预处理。假设所有的正确数据都走向ajaxsuccess句柄,所有异常的数据都走向error句柄,成功或者失败的结果不会互相穿插,我们在定义句柄时无疑可以省却很多if-else分支。

    这是其一,其二:所有成功的数据都是ResultEnry格式,所有的错误都是errorcode+errormsg散列。我们在前端拦截器error句柄可以凭借errorcode联动错误信息配置非常方便的进行报错弹窗,省去大量接口类异常的逻辑代码。

    所以此处统一错误处理应满足两点:

    1. 后台接口不应该捕获并处理数据异常
    2. 抛给前端的异常统一格式

    自定义返回实体

    略。参考另一篇《Spring boot自定义返回实体》

    统一异常处理的两种方法

    1. 使用注解ControllerAdvice
    2. 实现ErrorController

    本例选择ControllerAdvice+自定义异常实现统一规范。下面简单介绍两种方式。

    ControllerAdvice

    该注解定义一个异常类,类里面定义多种异常句柄。

    @ControllerAdvice
    public class WebExceptionHandler {
        @ExceptionHandler
        public Result<Object> unknownException(Exception e) {
            return ResultEntry.error(ResultEnum.UNKNOWN_ERROR);
        }
        @ExceptionHandler
        public Result<Object> ioException(IOException e) {
            return ResultEntry.error(ResultEnum.UNKNOWN_ERROR);
        }
    }
    

    此方法只能监听到控制器抛出的异常

    ErrorController

    此方式会让框架默认的BaseErrorController无效

    @RestController
    public class WebExceptionHandler implements ErrorController {
        public Result<Object> error(HttpServletRequest request, HttpServletResponse response) {
            return ResultEntry.error(ResultEnum.UNKNOWN_ERROR);
        }
    }
    

    自定义运行时异常

    业务代码捕捉到异常,然后通过自定义异常层层往上抛,结合状态码枚举ResultEnum可以达到统一格式精准提示。

    自定义异常ServiceException

    public class ServiceException extends RuntimeException{
        private ResultEnum error;
    
        public ServiceException(ResultEnum error) {
            this.error = error;
        }
    
        public ResultEnum getError() {
            return error;
        }
    
        public void setError(ResultEnum error) {
            this.error = error;
        }
    }
    

    ControllerAdvice异常句柄

    @ControllerAdvice
    public class ServiceExceptionHander {
        @ExceptionHandler(ServiceException.class)
        @ResponseBody
        public <T> ResponseEntity<Result<T>> handle(ServiceException e){
            ResponseEntity<Result<T>> result = ResultEntry.error(e.getError());
            return result;
        }
    }
    

    ResultEntry组装返回的数据结构,利用ResponseEntity传递给前端错误码和错误实体。所以如果接口能拿到正确的数据,返回HttpStatus.OK,否则返回HttpStatus.BAD_GATEWAY;前端也会相应的触发ajaxsuccess或者error句柄。

    public class ResultEntry<T> implements Serializable{
    
        public static <T> ResponseEntity<Result<T>> success(T o) {
            return ResultEntry.response(ResultEnum.SUCCESS, o);
        }
        
        public static <T> ResponseEntity<Result<T>> success() {
            return ResultEntry.response(ResultEnum.SUCCESS);
        }
    
        public static <T> ResponseEntity<Result<T>> response(ResultEnum enu, T o) {
            Result<T> result = new Result<T>();
            result.setMsg(enu.getMsg());
            result.setStatus(enu.getStatus());
            result.setBody(o);
            return new ResponseEntity<Result<T>>(result, HttpStatus.OK);
        }
    
        public static <T> ResponseEntity<Result<T>> response(ResultEnum enu) {
            Result<T> result = new Result<T>();
            result.setMsg(enu.getMsg());
            result.setStatus(enu.getStatus());
            return new ResponseEntity<Result<T>>(HttpStatus.OK);
        }
    
        public static <T> ResponseEntity<Result<T>> error(ResultEnum enu) {
            Result<T> result = new Result<T>();
            result.setMsg(enu.getMsg());
            result.setStatus(enu.getStatus());
            return new ResponseEntity<Result<T>>(result, HttpStatus.BAD_GATEWAY);
        }
    }
    

    测试

    //controller
    @RestController()
    public class UpgradeController {
        @Autowired
        private UpgradeService upgradeService;
    
        @RequestMapping(value = "upgrade/records", method = RequestMethod.GET)
        public ResponseEntity<Result<ResultPage<UpgradeRecordDTO>>> getUpgradeRecords() {
            ResultPage<UpgradeRecordDTO> data = upgradeService.getUpgradeRecords();
            return ResultEntry.success(data);
        }
    }
    
    //service
    @Service
    public class UpgradeService {
        @Autowired
        private UpgradeRecordRepository recordRepository;
        // 查升级记录
        public ResultPage<UpgradeRecordDTO> getUpgradeRecords() throws ServiceException {
            Pageable pageable = PageRequest.of(0, 10);
            return new ResultPage<>(recordRepository.findAll(pageable));
        }
    }
    
  • 相关阅读:
    window环境搭建zookeeper,kafka集群
    Spring Boot中使用Redis小结
    Spring Boot Mock单元测试学习总结
    Git快速入门进阶篇
    Git快速入门
    玩转Git入门篇
    Apache Kafka简介与安装(二)
    Apache Kafka简介与安装(一)
    Spring Boot中使用EhCache实现缓存支持
    java基础面试题(JVM篇)
  • 原文地址:https://www.cnblogs.com/longhx/p/15741036.html
Copyright © 2020-2023  润新知