HandlerExceptionResolver统一异常处理

作者: 编程界的小学生 | 来源:发表于2017-04-07 15:51 被阅读2416次

    由于前后分离,所以这里是统一返回JSON的格式

    自定义Exception

    package com.bshf.recipe.exception;
    
    public class BussinessException extends RuntimeException {
    
        private static final long serialVersionUID = 1L;
        
        private int code;
        private String msg;
        
        public BussinessException(String msg) {
            super();
            this.msg = msg;
        }
    
        public BussinessException(int code, String msg) {
            super();
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
        
    }
    

    自定义统一异常处理类

    package com.bshf.recipe.demo;
    
    import java.io.IOException;
    import java.util.Date;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.MediaType;
    import org.springframework.validation.BindException;
    import org.springframework.validation.FieldError;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.ModelAndView;
    
    import com.alibaba.fastjson.JSON;
    import com.bshf.recipe.exception.BussinessException;
    import com.bshf.recipe.vo.basic.ResultVO;
    
    /**
     * 异常处理类
     * 
     * @author 15620646321@163.com
     * @date 2017-04-07 12:47:03
     */
    @Order(-1000)
    public class ExceptionResolver implements HandlerExceptionResolver {
    
        private static Logger logger = LoggerFactory.getLogger("exceptionLog");
        
        @Override
        public ModelAndView resolveException(HttpServletRequest request,
                HttpServletResponse response, Object handler, Exception ex) {
            ResultVO result = new ResultVO();
            StringBuilder sb = new StringBuilder();
            
            //处理异常
            if(ex instanceof BussinessException) {
                resolverBussinessException(ex, sb, result);
            } else if (ex instanceof BindException) {
                resolverBindException(ex, sb, result);
            } else {
                resolverOtherException(ex, sb, result); 
            }
            
            result.setCode(0);
            result.setResult(sb);
            result.setTime(new Date());
            
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Cache-Control", "no-cache, must-revalidate");  
            try {
                response.getWriter().write(JSON.toJSONString(result));
            } catch (IOException e) {
                logger.error("与客户端通讯异常:" + e.getMessage(), e);
                e.printStackTrace();
            }
            
            logger.debug("异常:" + ex.getMessage(), ex);
            ex.printStackTrace();
            
            return new ModelAndView();
        }
        
        /*
         * 处理业务层异常 
         */
        private void resolverBussinessException(Exception ex, StringBuilder sb, ResultVO result) {
            BussinessException businessException = (BussinessException) ex;
            sb.append(businessException.getMsg());
            addResult(result, "业务异常");
        }
        
        /*
         * 处理参数绑定异常
         */
        private void resolverBindException(Exception ex, StringBuilder sb, ResultVO result) {
            BindException be = (BindException) ex;
            List<FieldError> errorList = be.getBindingResult().getFieldErrors();
            for (FieldError error : errorList) {
                sb.append(error.getObjectName());
                sb.append("对象的");
                sb.append(error.getField());
                sb.append("字段");
                sb.append(error.getDefaultMessage());
            }
            addResult(result, "参数传递异常");
        }
        
        /*
         * 处理其他异常
         */
        private void resolverOtherException(Exception ex, StringBuilder sb, ResultVO result) {
            sb.append(ex.getMessage());
            addResult(result, "其他异常");
        }
    
        /*
         * 封装code和msg
         */
        private void addResult(ResultVO result, String msg) {
            result.setMsg(msg);
        }
        
    }
    

    配置文件

    <!-- 定义异常处理器 -->
    <bean id="exceptionResolver" class="com.bshf.recipe.demo.ExceptionResolver"/>
    

    运行流程分析
    当你请求项目中某个接口时,如果报异常了,则会首先进入到这个自定义异常处理类中,然后通过判断异常类型来具体给客户端返回不同的信息提示。若接口没报异常,则此类的方法是不会运行的。

    问:为什么要加@Order(-1000)
    答:因为Spring默认有三个异常拦截器,里面的order属性分别为0,1,2,会首先去这三个拦截器中找匹配的异常,若有匹配的,则不会执行我们自定义的异常处理器。@Order(-1000)的作用就是将顺序提到第一位,先加载我们的,有符合异常条件的,则不会继续走其他三个默认的。(我们这里一定会走,因为首先是order变成了-1000,其次是我们对自定义异常、BindException和其他做了捕获,所以一定不会执行Spring默认的)

    问:为什么在最后添加了ex.printStackTrace();
    答:一切为了调试方便,这样可以将异常信息打印到控制台,方便查看。

    问:为什么要判断BindException?
    答:一切为了调试方便。他会配合javax.validation.*中的注解一起用,比如客户端传入的参数加上了如下

    @NotNull(message = "id不能为空")
    private Integer id;
    @NotEmpty(message = "title不能为空或空字符串")
    private String title;
    

    这时候我调用接口如果id和title都不传的话会进入我们的自定义异常处理类中去捕获,异常类型为BindException,会返回给客户端如下json:

    {
        "code": 0,
        "msg": "参数传递异常",
        "result": "demoIO对象的title字段title不能为空或空字符串demoIO对象的id字段id不能为空",
        "time": 1491551183087
    }
    

    这样就完成了统一异常处理。若没报异常则不会执行此方法,报异常则将异常信息返回给客户端方便调试。

    若有兴趣,欢迎来加入群,【Java初学者学习交流群】:458430385,此群有Java开发人员、UI设计人员和前端工程师。有问必答,共同探讨学习,一起进步!
    欢迎关注我的微信公众号【Java码农社区】,会定时推送各种干货:


    qrcode_for_gh_577b64e73701_258.jpg

    相关文章

      网友评论

      本文标题:HandlerExceptionResolver统一异常处理

      本文链接:https://www.haomeiwen.com/subject/jluhattx.html