主要讲解三种异常捕获形式:
- 页面跳转异常
- ajax异常
- 统一返回异常的形式
1.页面跳转异常
首先新建一个异常:
@Controller
@RequestMapping(value = "/err")
public class ErrorCtrl {
@RequestMapping(value = "/error")
public String error(){
int a = 1/0;
return "abcdefg";
}
}
新建异常处理工具类MyExceptionHandler:
@ControllerAdvice
public class MyExceptionHandler {
public static final String ERROR_VIEW = "my_error";
@ExceptionHandler(value = Exception.class)//指定拦截的异常
public Object errorHandler(HttpServletRequest request, HttpServletResponse response,Exception e) throws Exception{
e.printStackTrace();//打印异常信息
ModelAndView mv = new ModelAndView();
mv.addObject("exception",e);
mv.addObject("url",request.getRequestURL());//发生异常的路径
mv.setViewName(ERROR_VIEW);//指定发生异常之后跳转页面
return mv;
}
}
2.ajax异常
如果出现ajax异常而不捕获的话,就会一直loading,用户体验更加不好。所以ajax请求也需要处理。
我们首先要将之前创建的MyExceptionHandler类删除掉,避免其产生影响(只需要将类头部的@ControllerAdvice标注和方法头部的@ExceptionHandler标注注释掉即可)
然后新建ajax形式的异常处理工具类,命名为MyAjaxExceptionHandler:
@RestControllerAdvice
public class MyAjaxExceptionHandler {
@ExceptionHandler(value = Exception.class)
public CommonRspVo defaultErrorHandler(HttpServletRequest request,Exception e)throws Exception{
e.printStackTrace();
CommonRspVo rsp = new CommonRspVo("555",e.getMessage());
return rsp;
}
}
这里和之前页面跳转异常的不同在于类头部的标注换成了@RestControllerAdvice,其他的地方基本一致。在这里,当ajax异常发生时,我使用了一个简单的包装类返回信息给前台。
在ErrorCtrl中新增两个方法:
//跳转到发生ajax异常页面
@RequestMapping("/ajaxerror")
public String ajaxerror(){
return "thymeleaf/ajaxerror";
}
//发生ajax异常
@RequestMapping("/getAjaxerror")
public int getAjaxerror(){
int a = 1/0;
return a;
}
在浏览器中发起请求,跳转至ajaxerror.html页面,立即向后台发起ajax请求,并发生1/0异常,这时会被自定义的MyAjaxExceptionHandler捕获到,然后将异常信息等返回前台。
3.统一异常处理
web页面跳转和ajax异常的统一异常处理也是非常简单的,主要就是整合一下前两步的思路。可以判断前端请求request是否是ajax请求,然后采取不同的措施。
我们还是使用第一步中使用的MyExceptionHandler异常处理助手类,将之前写好的errorHandler方法注释掉,并在其中添加如下两个方法:
@ExceptionHandler(value = Exception.class)
public Object errorHandler(HttpServletRequest request,HttpServletResponse response,Exception e)throws Exception{
e.printStackTrace();
if(isAjax(request)){//是ajax请求
CommonRspVo rsp = new CommonRspVo("555",e.getMessage());
return rsp;
}else{//不是ajax请求
ModelAndView mv = new ModelAndView();
mv.addObject("exception",e);
mv.addObject("url",request.getRequestURL());//发生异常的路径
mv.setViewName(ERROR_VIEW);//指定发生异常之后跳转页面
return mv;
}
}
private boolean isAjax(HttpServletRequest request){//判断request是否是ajax请求
return (request.getHeader("X-Requested-With") != null
&& "XMLHttpRequest"
.equals( request.getHeader("X-Requested-With").toString()) );
}
其中,isAjax方法用于判断HttpServletRequest是否是ajax请求。
这里需要注意的一点是,我们需要将MyExceptionHandler类头部的@ControllerAdvice标注修改为@RestControllerAdvice,否则在进行ajax异常捕获之后会报出TemplateInputException。
我们可以根据之前的err/error和err/ajaxerror路径分别进行页面跳转异常和ajax异常的测试,通过dubug调试可以更清楚的看到程序的执行过程。