在之前使用springmvc,异常的处理都是在controller层中进行try--catch,在springmvc种如何设置报错时跳转的页面呢?统一进行异常处理

1.配置错误视图解析器

在mvc配置文件种添加下面的配置:

 <!--异常视图解析器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--默认异常视图-->
        <property name="defaultErrorView" value="error"/>
        <!--异常数据-->
        <property name="exceptionAttribute" value="ex"/>
        <!--进行细分,为定义异常返回指定的视图-->
        <property name="exceptionMappings">
            <props>
                <prop key="NullPointerException">
                    <!--发生异常时跳转的页面-->
                    error
                </prop>
                <prop key="ClassNotFoundException">
                    unauthorized
                </prop>
            </props>
        </property>
    </bean>

然后我们建一个简单的controller来验证这个视图解析器有没有起作用:

@Controller
@RequestMapping("/emp")
public class ExcetpionViewController {

    @GetMapping("/{empno}")
    public String fun1(@PathVariable("empno") int empno) throws ClassNotFoundException {
        if (empno == 5) {
            throw new NullPointerException("空指针异常");
        } else if (empno == 4) {
            throw new ClassNotFoundException("找不到类异常");
        }
        return "index";
    }
}

运行测试,输入不同的值,看发生异常时跳转的错误页面是否匹配;

2.在方法前面使用@ExceptionHandler注解,

该注解只能控制当前控制器汇中的异常,因此为了方便我们将其放在BaseController中,其他的controller都继承该BaseController,下面进行测试,将上一步的视图解析器注释掉:

public class BaseController {

    @ExceptionHandler({Exception.class})
    public String exception(Exception ex, Model model) {
        if (ex instanceof NullPointerException) {
            model.addAttribute("ex", ex);
            return "error";
        } else  {
            return "unauthorized";
        }
    }
}
@Controller
@RequestMapping("/emp")
public class ExcetpionViewController extends BaseController {

    @GetMapping("/{empno}")
    public String fun1(@PathVariable("empno") int empno) throws ClassNotFoundException {
        if (empno == 5) {
            throw new NullPointerException("空指针异常");
        } else if (empno == 4) {
            throw new ClassNotFoundException("找不到类异常");
        }
        return "index";
    }
}

浏览器发送请求,测试是否跳转响应地址。

3.使用 @ControllerAdvice+ @ ExceptionHandler 注解 (推荐使用)

与上面的方式差不多,不过使用这种方式避免了继承,controller不需要再继承BaseControlelr,发生异常时,就会调用该控制器中的方法

/**
 * @ControllerAdvice:
 * 相当于是AOP,面向切面,给每一个controller都横插了该控制器
 */
@ControllerAdvice
public class BaseController {

    @ExceptionHandler({Exception.class})
    public String exception(Exception ex, Model model) {
        if (ex instanceof NullPointerException) {
            model.addAttribute("ex", ex);
            return "error";
        } else  {
            return "unauthorized";
        }
    }
}

异步方式返回异常:

给方法添加@ResponseBody注解,返回json数据:可以定义一个实体,封装异常信息:

import lombok.Data;

/**
 * Data注解,可以自动生成set和get方法
 */
@Data
public class Result {
//    自定义异常状态码
    private int stats;
    //自定义异常信息
    private String messages;
}
/**
 * @ControllerAdvice:
 * 相当于是AOP,面向切面,给每一个controller都横插了该控制器
 */
@ControllerAdvice
public class BaseController {

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public Result exception(Exception ex) {
        Result result = new Result();
        if (ex instanceof NullPointerException) {
            result.setStats(408);
            result.setMessages("不能为空");
        } else if (ex instanceof ClassNotFoundException) {
            result.setStats(409);
            result.setMessages("找不到类");
        }
        return result;
    }
}

4.实现HandlerExceptionResolver接口

@Controller
@RequestMapping("/emp")
public class ExcetpionViewController implements HandlerExceptionResolver {

    @GetMapping("/{empno}")
    public String fun1(@PathVariable("empno") int empno) throws ClassNotFoundException {
        if (empno == 5) {
            throw new NullPointerException("空指针异常");
        } else if (empno == 4) {
            throw new ClassNotFoundException("找不到类异常");
        }
        return "index";
    }

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView();
        if (ex instanceof NullPointerException) {
            modelAndView.addObject("ex", ex.getMessage());
            modelAndView.setViewName("error");
        } else {
            modelAndView.setViewName("index");
        }
        return modelAndView;
    }
}