SpringBoot异常

1,默认的异常处理机制

当浏览器客户端请求一个不存在的页面或服务端处理发生异常时,SpringBoot默认会响应一个html文档内容,称作“Whitelabel Error Page”。

2,以下有四种异常处理方式

  • @ExceptionHandler 注解处理局部异常

  • 优点:可以自定义存储异常信息的key,和跳转视图的名称。

    缺点:异常捕获类必须在controller里面,所以会出现很多异常方法,因为他可以针对每一个异常

    @RestController
    public class TestController {
        @GetMapping("/test")
        public String test(){
            if(true){
                throw new NullPointerException("ExceptionHandler测试异常");
            }
            return "测试成功";
        }
        
        
    @ExceptionHandler(value = {NullPointerException.class})
     public ResponseEntity<String> handlerException(NullPointerException ex){
            return new ResponseEntity<>("我是一个空指针常:"+ex.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
    ​
        }
    
    
  • 使用 @ControllerAdvice + @ExceptionHandler 注解处理全局异常

  • 优点:可以根据不同的异常对不同的异常进行处理

    缺点:编写大量的异常处理方法,代码冗余

    @RestController
    public class TestController1 {
        @GetMapping("/test1")
        public String test1(){
            if(true){
                throw new NullPointerException("@ControllerAdvice + @ExceptionHandler测试异常");
            }
            return "测试成功";
        }
    }    
        
    @ControllerAdvice
    public class GlobalExceptionHandler {
        @ExceptionHandler(NullPointerException.class)
        @ResponseBody
        //1,创建异常捕获方法
        public ResponseEntity<String> handleException(Exception ex){
            return new ResponseEntity<>("我是空指针异常,我又来了:"+ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
        //还有多个异常处理,可以一直往下面写
    }
  • 配置 SimpleMappingExceptionResolver 处理异常

  • 优点:

    (1)配置相对简单,不需要编写大量的代码;

    (2)可以添加更多的异常处理映射;

    (3)可以在一个地方定义所有异常的处理方式,方便维护和查看

    缺点:只能处理简单的异常映射,对于复杂的异常处理场景可能不够灵活,而且这是静态配置

    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();
        properties.setProperty("java.lang.NUllPointerException","error");
        properties.setProperty("java.lang.RuntimeException","error");
        //设置异常与视图得映射信息
        resolver.setExceptionMappings(properties);
        return resolver;
    }
    
    
  • 自定义 HandlerExceptionResolver 类处理异常

      优点:

        (1)自定义异常可以根据具体业务需求来定义,并提供更有意义和准确描述的错误信息,以便于程序员和其他开发人员理解问题所在;

        (2)自定义异常可以携带额外的上下文信息,使得异常处理过程更具可读性和可理解性。

  • 利用自定义类处理异常应该继承现有合适的Java标准库中已存在的基础异常类(RuntimeException或Exception)

    // 数据操作异常定义
    
    SUCCESS("2000", "请求成功!"),
    
    BODY_NOT_MATCH("4000", "请求的数据格式不符!"),
    
    SIGNATURE_NOT_MATCH("4001", "请求的数字签名不匹配!"),
    
    DATA_EMPTY("4002","数据为空!"),
    
    DATA_NOT_ENOUGH("4003", "数据不足!"),
    
    NOT_FOUND("4004", "数据不存在或已删除!"),
    
    DATA_FOUND("4005", "数据已存在!"),
    
    CODE_NOT_MATCH("4006", "验证码错误!"),
    
    CODE_TIME_OUT("4007", "验证码已过期!"),
    
    PASSWORD_NOT_MATCH("4008", "密码不一致!"),
    
    INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
    
    SERVER_BUSY("5003", "服务器正忙,请稍后再试!");

    (1)创建异常接口,提供获取编码和描述方法

    public interface BaseErrorInfoInterface {
        //创建异常接口,提供获取编码和描述方法
        /**
         * 错误码
         * @return
         */
        String getResultCode();
    ​
        /**
         * 错误描述
         * @return
         */
        String getResultMsg();
    }

    (2)创建异常枚举类,实现异常服务接口类的方法,并且定义数据操作异常的类型

    public enum ExceptionEnum implements BaseErrorInfoInterface{
        // 数据操作异常定义
        SUCCESS("2000", "请求成功!"),
        BODY_NOT_MATCH("4000", "请求的数据格式不符!"),
        SIGNATURE_NOT_MATCH("4001", "请求的数字签名不匹配!"),
        DATA_EMPTY("4002","数据为空!"),
        DATA_NOT_ENOUGH("4003", "数据不足!"),
        NOT_FOUND("4004", "数据不存在或已删除!"),
        DATA_FOUND("4005", "数据已存在!"),
        CODE_NOT_MATCH("4006", "验证码错误!"),
        CODE_TIME_OUT("4007", "验证码已过期!"),
        PASSWORD_NOT_MATCH("4008", "密码不一致!"),
        INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
        SERVER_BUSY("5003", "服务器正忙,请稍后再试!");
        ;
        //错误码
        private String resultCode;
        //错误信息
        private String resultMsg;
        
        ExceptionEnum(String resultCode,String resultMsg){
            this.resultCode=resultCode;
            this.resultMsg=resultMsg;
        }
        @Override
        public String getResultMsg() {
            return resultMsg;
        }
        @Override
        public String getResultCode() {
            return resultCode;
        }
    }

    (3)创建自定义异常,继承RuntimeException

    public class MyException extends RuntimeException{
        private static final long serialVersionUID = 1L;
    ​
        /**
         * 错误码
         */
        protected String errorCode;
        /**
         * 错误信息
         */
        protected String errorMsg;
    ​
        public MyException() {
            super();
        }
    ​
        public MyException(BaseErrorInfoInterface errorInfoInterface) {
            super(errorInfoInterface.getResultCode());
            this.errorCode = errorInfoInterface.getResultCode();
            this.errorMsg = errorInfoInterface.getResultMsg();
        }
    ​
        public MyException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
            super(errorInfoInterface.getResultCode(), cause);
            this.errorCode = errorInfoInterface.getResultCode();
            this.errorMsg = errorInfoInterface.getResultMsg();
        }
    ​
        public MyException(String errorMsg) {
            super(errorMsg);
            this.errorMsg = errorMsg;
        }
    ​
        public MyException(String errorCode, String errorMsg) {
            super(errorCode);
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
        }
    ​
        public MyException(String errorCode, String errorMsg, Throwable cause) {
            super(errorCode, cause);
            this.errorCode = errorCode;
            this.errorMsg = errorMsg;
        }
    ​
        public String getErrorCode() {
            return errorCode;
        }
    ​
        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    ​
        public String getErrorMsg() {
            return errorMsg;
        }
    ​
        public void setErrorMsg(String errorMsg) {
            this.errorMsg = errorMsg;
        }
    ​
        @Override
        public Throwable fillInStackTrace() {
            return this;
        }
    }

    (4)创建返回响应实体类: 属于规范方法返回值结构体的类,也有利于一致化后端所有接口的返回结构,方便前端(客户端)读取所需要的数据;异常处理返回客户端的数据将采用该类的数据结构

    @Data
    @NoArgsConstructor
    public class ResponseHelper<T> {
        //响应状态码
        private String code;
        //响应信息
        private String msg;
        //响应数据
        private T data;
        public ResponseHelper(String code,String msg){
            this.code=code;
            this.msg=msg;
        }
        public ResponseHelper(String code,String msg,T data){
            this.code=code;
            this.msg=msg;
            this.data=data;
        }
        
        public static <T> ResponseHelper<T> success() {
            return new ResponseHelper<T>("200", "success", null);
        }
    ​
        public static <T> ResponseHelper<T> success(String msg) {
            return new ResponseHelper<T>("200", msg, null);
        }
    ​
        public static <T> ResponseHelper<T> success(String code, String msg) {
            return new ResponseHelper<T>(code, msg, null);
        }
    ​
        public static <T> ResponseHelper<T> success(T data) {
            return new ResponseHelper<T>("200", "success", data);
        }
    ​
        public static <T> ResponseHelper<T> success(String code, String msg, T data) {
            return new ResponseHelper<T>(code, msg, data);
        }
    ​
        public static <T> ResponseHelper<T> fail() {
            return new ResponseHelper<>("500", "Fail", null);
        }
    ​
        public static <T> ResponseHelper<T> fail(String code, String msg) {
            return new ResponseHelper<>(code, msg, null);
        }
    }

    (5) 创建全局异常处理控制类: 处理各类异常的业务(即根据不同的异常类型向客户端返回相应的信息)

    @ControllerAdvice
    public class GlobalExceptionHandler {
    @ExceptionHandler(value = {MyException.class})
        public @ResponseBody ResponseHelper myExceptionHandler(MyException e) {
            return ResponseHelper.fail(e.errorCode, e.getErrorMsg());
        }
    }
    
    

    (6)创建测试接口

    @GetMapping("/test3")
    public ResponseHelper test(){
        if (true){
            throw new MyException(ExceptionEnum
                    .CODE_NOT_MATCH
                    .getResultCode(),              ExceptionEnum.CODE_NOT_MATCH
                         .getResultMsg());
        }
        return ResponseHelper.success("Success");
    }
    
    
SpringBoot提供了一套默认的异常处理机制。一旦程序出现异常SpringBoot会向/error的URL发送请求,并通过BasicErrorController来处理该请求。默认情况下,SpringBoot会跳转到默认显示异常信息的页面来展示异常信息。如果我们希望将所有的异常统一跳转到自定义的错误页面,可以在src/main/resources/templates目录下创建一个名为error.html的页面。通过覆盖默认的错误页面,我们可以实现自定义的异常处理。 除了使用SpringBoot的默认配置外,还可以通过自定义错误页面来处理异常。我们可以在src/main/resources/templates目录下创建error.html页面,并将其命名为error。通过这种方式,我们可以自定义错误页面的内容和样式来展示异常信息。 在处理异常的过程中,可以关注ErrorMvcAutoConfiguration中的三个关键点。通过对SpringBoot错误处理机制源码的跟踪,我们可以更深入地了解异常处理的实现细节。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot异常处理](https://blog.youkuaiyun.com/Linging_24/article/details/126077782)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringBoot 异常处理详解](https://blog.youkuaiyun.com/qq_42402854/article/details/91415966)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值