zoukankan      html  css  js  c++  java
  • springboot全局异常处理

    项目中遇到运行时异常,总不能每个异常处理都去添加try catch逻辑,甚至有的时候一个偶然条件发生而导致异常,而我们没有进行对应的处理则会直接给请求者返回未知的错误,这在正式的上线的项目中是不允许,所以我们来配置全局异常处理

    今天讲解一下如何在SpringBoot实现全局异常机制,在没有用springboot大家要实现这一的功能基本上都是通过aop的思想,还是有点麻烦,而现在springboot中对它要进行了一次封装,开发者使用起来更加的简单,接下先通过代码演示效果,然后再分析一下原理,好了废话不多说直接上代码,看代码结构:

    1、使用到的注解:@ControllerAdvice注解是用来配置控制器通知的,我们可以配置过滤拦截具体一种或者多种类型的注解,添加annotations属性即可,在类的上方我们配置了@ControllerAdvice的annotations属性值为RestController.class,也就是只有添加了@RestController注解的控制器才会进入全局异常处理;因为我们全局返回的都是统一的Json格式的字符串,所以需要再类上配置@ResponseBody注解;@ExceptionHandler注解用来配置需要拦截的异常类型,默认是全局类型,可以通过value属性配置只对某个类型的异常起作用;@ResponseStatus注解用于配置遇到该异常后返回数据时的StatusCode的值,我们这里默认使用值500

    定义一个返回的DTO工具类

    //
    // 定义一个返回的DTO工具类
    //
    
    package com.zkml.common.obj.dto;
    
    import com.zkml.common.obj.enums.ResultStatusEnum;
    import java.io.Serializable;
    
    public class ResultModelDTO<T> implements Serializable {
        private ResultStatusEnum result;
        private Long code;
        private String message;
        private T model;
    
        public ResultModelDTO() {
        }
    
        public boolean successResult() {
            return this.result.equals(ResultStatusEnum.success);
        }
    
        public boolean failResult() {
            return !this.successResult();
        }
    
        public ResultModelDTO(ResultStatusEnum result, long code, String message, T model) {
            this.result = result;
            this.code = Long.valueOf(code);
            this.message = message;
            this.model = model;
        }
    
        public ResultModelDTO(ResultStatusEnum result, ResultCode remoteResultCode, T model) {
            this(result, remoteResultCode.getCode(), remoteResultCode.getMessage(), model);
        }
    
        public ResultStatusEnum getResult() {
            return this.result;
        }
    
        public void setResult(ResultStatusEnum result) {
            this.result = result;
        }
    
        public Long getCode() {
            return this.code;
        }
    
        public void setCode(Long code) {
            this.code = code;
        }
    
        public String getMessage() {
            return this.message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public T getModel() {
            return this.model;
        }
    
        public void setModel(T model) {
            this.model = model;
        }
    }
    

    定义一个全局异常处理类

    package com.springboot.exception.global_excep;
     
    import com.springboot.exception.json.JsonResult;
    import org.springframework.beans.ConversionNotSupportedException;
    import org.springframework.beans.TypeMismatchException;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.http.converter.HttpMessageNotWritableException;
    import org.springframework.web.HttpMediaTypeNotAcceptableException;
    import org.springframework.web.HttpRequestMethodNotSupportedException;
    import org.springframework.web.bind.MissingServletRequestParameterException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import lombok.extern.slf4j.Slf4j 
    import java.io.IOException;
     
    /**
     * @Author fanghui
     * @Description 全局异常拦截器
     * @Date 16:38 2019/8/14
     * @Modify By
     */
    @ControllerAdvice
    @ResponseBody
    @Slf4j 
    public class GlobalExceptionHandler {
     
     private String getMessage(BindingResult result) {
            return result.getFieldErrors().stream().map(error -> {
                return error.getField() + "[" + error.getRejectedValue() + "]:" + error.getDefaultMessage();
            }).collect(Collectors.joining(", "));
        }
    
        /**
         * 捕获 controller 实体类参数@Validate验证报错
         *
         * @param e
         * @param request
         * @param response
         * @return
         */
        @ExceptionHandler(BindException.class)
        @ResponseBody
        public JsonResult validExceptionHandler(BindException e, HttpServletRequest request, HttpServletResponse response) {
            return JsonResult.error(getMessage(e.getBindingResult()), ErrorCode.ILLEGAL_PARAM.name());
        }
    
        /**
         * 捕获 普通方法传参@Validate验证报错
         *
         * @param e
         * @param request
         * @param response
         * @return
         */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        @ResponseBody
        public JsonResult validExceptionHandler(MethodArgumentNotValidException e, HttpServletRequest request, HttpServletResponse response) {
            return JsonResult.error(getMessage(e.getBindingResult()), ErrorCode.ILLEGAL_PARAM.name());
        }
    
        /**
         * 捕获 controller 平铺参数@Validate验证报错
         *
         * @param e
         * @param request
         * @param response
         * @return
         */
        @ExceptionHandler(ConstraintViolationException.class)
        @ResponseBody
        public JsonResult validExceptionHandler(ConstraintViolationException e, HttpServletRequest request, HttpServletResponse response) {
            return JsonResult.error(e.getMessage(), ErrorCode.ILLEGAL_PARAM.name());
        }
    
        //运行时异常
        @ExceptionHandler(RuntimeException.class)
        public String runtimeExceptionHandler(HttpServletRequest request,RuntimeException ex) {
             log.info("请求路径:"+request.getRequestURL().toString()+"+"RuntimeException :"+ex);
            return ResultModelUtil.failResult(DefaultResultCodeEnum.ADD_ERROR);
        }
     
        //空指针异常
        @ExceptionHandler(NullPointerException.class)
        public String nullPointerExceptionHandler(HttpServletRequest request,NullPointerException ex) {
              log.info("请求路径:"+request.getRequestURL().toString()+"+"NullPointerException :"+ex);
            return ResultModelUtil.failResult(DefaultResultCodeEnum.ADD_ERROR);
        }
     
        //类型转换异常
        @ExceptionHandler(ClassCastException.class)
        public String classCastExceptionHandler(HttpServletRequest request,ClassCastException ex) {
             log.info("请求路径:"+request.getRequestURL().toString()+"+"ClassCastException :"+ex);
            return resultFormat(3, ex);
        }
     
        //IO异常
        @ExceptionHandler(IOException.class)
        public String iOExceptionHandler(HttpServletRequest request,IOException ex) {
            log.info("请求路径:"+request.getRequestURL().toString()+"+"IOException :"+ex);
            return resultFormat(4, ex);
        }
     
        //未知方法异常
        @ExceptionHandler(NoSuchMethodException.class)
        public String noSuchMethodExceptionHandler(NoSuchMethodException ex) {
            return resultFormat(5, ex);
        }
     
        //数组越界异常
        @ExceptionHandler(IndexOutOfBoundsException.class)
        public String indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
            return resultFormat(6, ex);
        }
     
        //400错误
        @ExceptionHandler({HttpMessageNotReadableException.class})
        public String requestNotReadable(HttpMessageNotReadableException ex) {
            System.out.println("400..requestNotReadable");
            return resultFormat(7, ex);
        }
     
        //400错误
        @ExceptionHandler({TypeMismatchException.class})
        public String requestTypeMismatch(TypeMismatchException ex) {
            System.out.println("400..TypeMismatchException");
            return resultFormat(8, ex);
        }
     
        //400错误
        @ExceptionHandler({MissingServletRequestParameterException.class})
        public String requestMissingServletRequest(MissingServletRequestParameterException ex) {
            System.out.println("400..MissingServletRequest");
            return resultFormat(9, ex);
        }
     
        //405错误
        @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
        public String request405(HttpRequestMethodNotSupportedException ex) {
            return resultFormat(10, ex);
        }
     
        //406错误
        @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
        public String request406(HttpMediaTypeNotAcceptableException ex) {
            System.out.println("406...");
            return resultFormat(11, ex);
        }
     
        //500错误
        @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
        public String server500(RuntimeException ex) {
            System.out.println("500...");
            return resultFormat(12, ex);
        }
     
        //栈溢出
        @ExceptionHandler({StackOverflowError.class})
        public String requestStackOverflow(StackOverflowError ex) {
            return resultFormat(13, ex);
        }
     
        //除数不能为0
        @ExceptionHandler({ArithmeticException.class})
        public String arithmeticException(ArithmeticException ex) {
            return resultFormat(13, ex);
        }
     
     
        //其他错误
        @ExceptionHandler({Exception.class})
        public String exception(Exception ex) {
            return resultFormat(14, ex);
        }
     
        private <T extends Throwable> String resultFormat(Integer code, T ex) {
            ex.printStackTrace();
            log.error(String.format(logExceptionFormat, code, ex.getMessage()));
            return JsonResult.failed(code, ex.getMessage());
        }
     
    }
    

    除了上面的运行时异常之外,还有一个是专门来处理业务异常的,接下来我们再来处理一个自定义业务异常类:

    自定义业务异常类BaseException

    package com.izkml.mlyun.framework.common.exception;
    
    public class BaseException extends RuntimeException {
        private String errorCode;
    
        public String getErrorCode() {
            return this.errorCode;
        }
    
        public void setErrorCode(String errorCode) {
            this.errorCode = errorCode;
        }
    
        public BaseException(String errorCode, String message) {
            this(errorCode, message, (Throwable)null);
        }
    
        public BaseException(String errorCode, String message, Throwable cause) {
            super(message, cause);
            this.errorCode = errorCode;
        }
    
        public BaseException(ErrorEnum errorEnum) {
            this(errorEnum.getCode(), errorEnum.getText(), (Throwable)null);
        }
    
        public BaseException(ErrorEnum errorEnum, Throwable cause) {
            this(errorEnum.getCode(), errorEnum.getText(), cause);
        }
    }
    

    SpringMVC@ResponseStatus注解的使用

    有时候,我们在实战项目中并不关心返回消息体的内容,前端只关系后端返回的状态码到底是什么,这个时候我们就要做的专业点,那么此时这个注解就派上用场了

        //405-Method Not Allowed
        @ExceptionHandler(HTTPRequestMethodNotSupportedException.class)
        @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)  //这个HttpStatus是个枚举类,可以点击进去有很多不同枚举
        public Map<String,Object> server500(RuntimeException ex) {
            Map<String,Object> map = new HashMap<String,Object>();
            map.put("code",400);
            map.put("message",e.getMessage());
            return map;
        }
    

    总结

    我们开发无论什么服务都大体分为三层,controller,service,dao;其中servic一般不做任何系统类型异常处理(RuntimeException和Exception),只关注业务分析,但是有一种情况需要往上进行抛异常(比如,业务层中车牌号重复,需要告诉上游你的车牌号已经重复,需要一层一层的往上进行抛直到前端页面告知用户);除了这种业务需要判断的异常往上抛之外,异常需要在controller进行捕捉,通过try..catch..进行捕获或者使用全局异常进行拦截,事实上,对于服务器来说,它是200,正常返回的,而对不业务模块来说,它的状态是个500,嘿嘿,这点要清楚

  • 相关阅读:
    剑指offer(4)
    剑指offer(3)
    剑指offer(2)
    剑指offer(1)
    (二)Wireshark的实用表格
    RedHat Enterprise Linux 6.4使用yum安装出现This system is not registered to Red Hat Subscription Management
    Android:简单的图片浏览器
    rpm和yum
    良心推荐!GitHub14400颗星!非常不错的机器学习指南
    Python中免验证跳转到内容页的实例代码
  • 原文地址:https://www.cnblogs.com/fangh816/p/13360367.html
Copyright © 2011-2022 走看看