springboot中对于异常的处理——返回html

异常处理——返回html

对于日常开发而言,因是否采用前后端分离的方式,异常信息的处理也将分为两类,

  • 返回html页面,
  • 直接返回json数据

本文主要介绍返回html的方式

底层原理

对于在doDispatch执行过程中产生的异常(404除外,算是特殊情况),在执行视图解析的过程中,会对产生的异常逐一通过各种异常解析器进行解析,异常解析器默认有两种,一种是默认用于给默认信息赋值的,没什么用,另一个是系统自带的HandlerExceptionResolverComposite,在它里面藏了三个异常解析器,如下图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I7qLwrEX-1648953186274)(http://www.chajianbao.store:8001/upload-images/2022/04/03/1648952186618.png “图片title”)]

  • ExceptionHandlerExceptionResolver:基于@ControllerAdvice和@ExceptionHandler注解的解析器,返回值和controller类似,最后都会封装成ModelAndView对象,因此可以指定异常数据显示的视图地址(例如放到error/error.html),或者和下面两个一样,手动调用一下response.sendError()
  • ResponseStatusExceptionResolver:基于@ResponseStatus的解析器,一般和自定义的异常类一起使用,该方法内部会根据@ResponseStatus注解的信息请求转发到/error中(底层是调用了response.sendError(statusCode,resolvedReason))
  • DefaultHandlerExceptionResolen:springboot中提供的在框架运行过程中可能出现异常进行的处理的默认异常处理器,同样的根据异常请求转发到/error中

1.基于@ControllerAdvice和@ExceptionHandler注解方法

@Slf4j
@ControllerAdvice
public class GlobalException {
    /**
     * java.lang.ArithmeticException
     * 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视图的指定
     * 参数 Exception e:会将产生异常对象注入到方法中
     */
    @ExceptionHandler(value={java.lang.ArithmeticException.class,Exception.class})//可以写多个
    public String arithmeticExceptionHandler(Exception e){//返回值可以直接就是视图名
		logger.error("Exception : {}",e);
        return mv;
    }
    /**
     * java.lang.NullPointerException
     * 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视图的指定
     * 参数 Exception e:会将产生异常对象注入到方法中
     */
    @ExceptionHandler(value={java.lang.NullPointerException.class})
    public ModelAndView nullPointerExceptionHandler(Exception e){//返回值也可是是ModelAndView
        logger.error("Exception : {}",e);
        ModelAndView mv = new ModelAndView();
        mv.addObject("error", e.toString()+" -- advice");
        mv.setViewName("error2");
        return mv;
    }
     /**
     * java.lang.NullPointerException
     * 该方法需要没有返回值:直接指定返回的状态码(和信息),直接返回
     * 参数 Exception e:会将产生异常对象注入到方法中
     */
    @ExceptionHandler(value={IOException.class})
    public void IOExceptionHandler(HttpServletResponse response,Exception e){//返回值为空,直接
        try {
            response.sendError(405);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return;
    }
}

2.基于@ResponseStatus注解方法

  • 首先定义一个自定义异常
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR,reason = "服务器异常")
public class TestException extends RuntimeException {
}
  • 编写测试类
@RequestMapping(value = "/test20")
@ResponseBody
public void test20( String name){
    if (null==name){
        //在运行中抛出自定义异常
    	throw new TestException();
    }
    System.out.println("======");
}

当程序抛出自定义异常时,会由ResponseStatusExceptionResolver进行处理,整合@ResponseStatus注解中填写的信息将其请求转发到/error,然后走默认的那条路径

3.自定义异常解析器

以上两种方式是sprinboot底层帮我们自动封装好的解析器,因此只要拿出来用就可以了,我们也可以自定义一个异常解析器,只要实现HandlerExceptionResolver接口就并将该解析器加入到容器中即加入@Component注解

@Slf4j
@Order(value = Ordered.HIGHEST_PRECEDENCE)//设置优先级,默认是最低的优先级
@Component//加入容器中
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        log.error("exception:{}",ex);
        try {
            response.sendError(501,"我自定义的错误");//前者对应status,后者对应message
        } catch (IOException e) {
            e.printStackTrace();
        }
        //必须加,因为如果不加,mv为空的话,还会继续遍历后面的解析器,会将当前的设置重置
        //当然,因为返回的是mv对象,因此也可以指定model和view的值,进行正常的域名解析跳转页面
        return new ModelAndView();
    }
}

注意:

  • 基本步骤:实现接口,注入容器,要有返回值(不能为空),要设置优先级(默认最低)
  • 只能返回mv对象,不能返回别的,因为底层直接对接mv,没有返回值处理器的过程
  • 会识别所有的异常

2022-04-03 10:20:03 星期日

你可能感兴趣的:(java,spring,intellij-idea)