• springboot 错误处理


    在 java web开发过程中,难免会有一些系统异常或人为产生一些异常。在 RESTful springboot 项目中如何优雅的处理?

    分析:在RESTful 风格的springboot 项目中,返回的都是 body 对象,所以定义一个结果基类,其中包含 status,message,data(请求方法的返回结果),是比较合适的。

    如果定义多个异常类进行处理,会比较麻烦。比如StudentNotExistsException、StudentExistsException。。。等,并且不能指定错误码,不方便前端根据错误码进行处理。

    说明:一般的spring mvc模型处理流程如下

    一般controller层 -> Service层 -> Dao层。

    1.controller层,接受请求,进行分页,DTO对象封装操作。

    2.service层,执行逻辑,控制并发,事务。

    3.Dao层,与数据库交互。

    使用一个学生表的处理进行说明:

    1、定义常见的错误枚举 StudentExceptionEnum

    public enum StudentExceptionEnum {
        STUDENT_NOT_EXIST(1004,"学生不存在,请确认后再查"),
        STUDENT_EXIST(1005,"学生已存在");
    
        private Integer status;
        private String comment;
    
        StudentExceptionEnum(Integer status, String comment) {
            this.status = status;
            this.comment = comment;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
        public String getComment() {
            return comment;
        }
    
        public void setComment(String comment) {
            this.comment = comment;
        }
    }

    2 定义一个基本的处理结果类 RequestResult

    @Data
    public class RequestResult {
        private String message;
        private Integer status;
        private Object data;
    
        public RequestResult(String message, Integer status, Object data) {
            this.message = message;
            this.status = status;
            this.data = data;
        }
    
        public RequestResult(String message, Integer status) {
            this.message = message;
            this.status = status;
        }
    
        public RequestResult(String message, StudentExceptionEnum requestExceptionEnum) {
            this.message = message;
            this.status = requestExceptionEnum.getStatus();
        }
    
        public RequestResult() {
            status = 200;
            message = "ok";
        }
    
        public static RequestResult OK(Object data) {
            RequestResult result = new RequestResult();
            result.setData(data);
            return result;
        }
    
        public static RequestResult EXCEPTION(String message, Integer status) {
            return new RequestResult(message, status);
        }
    
        public static RequestResult EXCEPTION(String message, StudentExceptionEnum requestExceptionEnum) {
           return new RequestResult(message, requestExceptionEnum);
        }
    
    }

    3 实体类 Student

    @Data
    public class Student implements Serializable{
        private String id;
        private String nickname;
        private String name;
        private int age;
        private String sex;
        private String address;
    
    
        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this);
        }
    }
    View Code

    4 处理请求,添加学生,nickname 必填项。此处只显示 Service 片段代码

    @Override
        public RequestResult addStudent(Student student) {
            if (studentDao.queryIdByNickname(student.getNickname()) == null) {
                studentDao.addStudent(student);
                System.out.println("添加成功");
                student = studentDao.queryByNickname(student.getNickname());
                return RequestResult.OK(student);
            } else {
                return RequestResult.EXCEPTION("用户" + student.getNickname() + "已存在", StudentExceptionEnum.STUDENT_EXIST);
            }
        }

    5 此时,已经完成了基本的处理情况。下面就进行基本的测试了

    5.1 添加一个新同学信息

    5.2 再次添加让其出现异常测试

    二、到此基本已大功告成,但是,对于基本的运行时异常没有处理,直接返回给前端会很不友好。所以要定义一个全局的 RuntimeException 异常处理类。

    此处需要使用的关键标注: @ExceptionHandler

    用法有两种 1)在处理请求的 Controller 中添加 @ExceptionHandler,此时该方法只会处理该 Controller 抛出的异常。

    2)将其用在全局的异常处理类中,全局异常处理类需要使用  @RestControllerAdvice 或 @ControllerAdvice 标记

    我们需要处理全局的 RuntimeException,所以我们使用第二种方法。当然,这样处理是为了客户友好型,我们还是要处理这种错误,怎么办?就需要将错误的信息记录下来,方便以后分析处理。此处使用 logger 进行记录。代码如下

    @RestControllerAdvice
    public class BaseExceptionHandler {
        private static Logger logger = LoggerFactory.getLogger(BaseExceptionHandler.class);
    
        @ExceptionHandler(value = RuntimeException.class)
        public RequestResult exceptionHandler(HttpServletRequest request,Exception e) {
            logError(request,e);
            return RequestResult.EXCEPTION("内部处理异常,工程师正在抓紧抢修,请稍后再来...",500);
        }
    
        public static void logError(HttpServletRequest request, Exception e) {
    
            logger.error("请求地址:" + request.getRequestURL());
            logger.error("请求方法:" + request.getMethod());
            logger.error("请求IP:" + getRemoteIp(request));
            logger.error("错误详情:");
            StackTraceElement[] error = e.getStackTrace();
            for (StackTraceElement stackTraceElement : error) {
                logger.error(stackTraceElement.toString());
            }
        }
    
        public static String getRemoteIp(HttpServletRequest request) {
            String ip = request.getHeader("X-Forwarded-For");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("HTTP_CLIENT_IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getHeader("HTTP_X_FORWARDED_FOR");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                    ip = request.getRemoteAddr();
                }
            } else if (ip.length() > 15) {
                String[] ips = ip.split(",");
                for (int index = 0; index < ips.length; index++) {
                    String strIp = (String) ips[index];
                    if (!("unknown".equalsIgnoreCase(strIp))) {
                        ip = strIp;
                        break;
                    }
                }
            }
            return ip;
        }
    }

    进行测试看是否生效:

    修改添加学生信息代码如下:

    public RequestResult addStudent(Student student) {
            int a = 1/0;
            
            if (studentDao.queryIdByNickname(student.getNickname()) == null) {
                studentDao.addStudent(student);
                System.out.println("添加成功");
                student = studentDao.queryByNickname(student.getNickname());
                return RequestResult.OK(student);
            } else {
                return RequestResult.EXCEPTION("用户'" + student.getNickname() + "'已存在", StudentExceptionEnum.STUDENT_EXIST);
            }
        }

    进行测试

    后台打印错误信息

    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : 请求地址:http://localhost:8080/demo1/student
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : 请求方法:POST
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : 请求IP:0:0:0:0:0:0:0:1
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : 错误详情:
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : com.huitong.demo.service.StudentService.addStudent(StudentService.java:71)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : com.huitong.demo.controller.StudentController.addStudent(StudentController.java:38)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : java.lang.reflect.Method.invoke(Method.java:498)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776)
    2018-03-26 17:01:19.125 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    2018-03-26 17:01:19.129 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    2018-03-26 17:01:19.130 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    2018-03-26 17:01:19.131 ERROR 9136 --- [nio-8080-exec-2] c.h.d.controller.BaseExceptionHandler    : java.lang.Thread.run(Thread.java:745)
    2018-03-26 17:01:19.133  WARN 9136 --- [nio-8080-exec-2] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: java.lang.ArithmeticException: / by zero
  • 相关阅读:
    从上往下,从左往右
    idea jar包破解
    StarUML 2下载、安装、破解全过程
    windows10 找回windows照片查看器的方法
    Tomcat报错Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    Java基于SSM在线学习系统设计与实现
    多个iframe,删除详情页时刷新同级iframe的table list
    Eclipse项目工程导入到IDEA继续开发-超详细
    MySQL用B+树做索引
    彻底禁用Chrome插件停用开发者模式提示插件version.dll
  • 原文地址:https://www.cnblogs.com/zhaopengcheng/p/8652116.html
Copyright © 2020-2023  润新知