统一处理某一类异常,能够减少代码的重复度和复杂度,有利于代码的维护。
Spring 统一异常处理有 4 种方式,分别为:
使用 @ ExceptionHandler 注解
实现 HandlerExceptionResolver 接口
使用 @controlleradvice 注解
使用 @Restcontrolleradvice注解
使用@ExceptionHandler注解作用在方法上面,参数是具体的异常类型。
一旦系统抛出这种类型的异常时,会引导到该方法来处理。
但是它的缺陷很明显,处理异常的方法和出错的方法(或者异常最终抛出来的地方)必须在同一个controller,不能全局控制。
@GetMapping("/gooderr")
public Good test3(Good good){
int i=5/0;
return good;
}
//如果不加这个 就会报500页面错误
@ExceptionHandler(Exception.class)
public ModelAndView myException(Exception e) {
ModelAndView error = new ModelAndView("error");
error.addObject("error", e.getMessage());
return error;
}
编写一个error.jsp文件
<%@page pageEncoding="UTF-8" language="java" contentType="text/html;UTF-8" %>
这是错误页面
${error}
springmvc提供一个HandlerExceptionResolver接口,自定义全局异常处理器必须要实现这个接口,如下:
创建一个包:
handlerexr包下创建
@Component
public class HandlerResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) {
ModelAndView mv=new ModelAndView();
mv.addObject("msg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
测试运行:http://localhost:8080/gooderr
分类异常处理:创建三个异常页面 复制三个 分别是空指针,Arithmetic计算异常,全局异常
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
测试成功,欢迎来到我的世界
空指针异常:${msg}
先验证是否正确:http://localhost:8080/gooderr
异常验证controller:
@GetMapping("/gooderr")
@ResponseBody
public Good test2(Good good) throws BizException {
if(good.getNum()==1){
int i=5/0;
}else if (good.getNum()==2){
String name=null;
name.equals("abc");
}
return good;
}
访问地址:http://localhost:8080/gooderr?num=1 计算异常
http://localhost:8080/gooderr?num=2 空指针异常
内容输出:
@Component
public class HandlerResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) {
ModelAndView mv=new ModelAndView();
if(e instanceof ArithmeticException){
mv.setViewName("Arithmetic");
mv.addObject("msg",e.getMessage());
}
if(e instanceof NullPointerException){
mv.setViewName("nullpoint");
}
mv.addObject("msg",e.toString());
/*
mv.addObject("msg",e.getMessage());
mv.setViewName("error");*/
return mv;
}
}
直接测试
@ExceptionHandler 可以返回 ModelAndView 定制异常视图。
@ControllerAdvice 是一个增强的 Controller,@ExceptionHandler 可以拦截特定的异常,因此可以更精确的配置异常处理逻辑。
创建一个类advice中: MyExceptionAdvice
@ControllerAdvice
public class MyExceptionAdvice {
@ExceptionHandler(NullPointerException.class)
public ModelAndView processException(NullPointerException ex){
ModelAndView mv = new ModelAndView("nullpoint");
mv.addObject("msg",ex.toString());
return mv;
}
@ExceptionHandler(ArithmeticException.class)
public ModelAndView processException2(ArithmeticException ex){
ModelAndView mv = new ModelAndView("arith");
mv.addObject("msg",ex.toString());
return mv;
}
}
测试运行:
简写方式:
@ExceptionHandler(Exception.class)
public ModelAndView processException(Exception e){
ModelAndView mv=new ModelAndView();
if(e instanceof ArithmeticException){
mv.setViewName("arith");
mv.addObject("msg",e.getMessage());
}
if(e instanceof NullPointerException){
mv.setViewName("nullpoint");
mv.addObject("msg",e.toString());
}
// mv.addObject("msg",e.toString());
return mv;
}
但是使用第一种方式还是比较清晰的:
public class BizException extends Exception{
private int code;
public BizException(String msg){
super(msg);
}
public BizException(int code,String msg){
super(msg);
this.code=code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
在MyExceptionAdvice中加一个方法:
@ExceptionHandler(BizException.class)
public ModelAndView processException2(BizException e){
ModelAndView mv=new ModelAndView();
mv.addObject("msg",e.getCode()+"-->"+e.toString());
mv.setViewName("biz");
return mv;
}
创建一个Biz的异常jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
测试成功,欢迎来到我的世界
自己定义的异常:${msg}
controller中修改:
@GetMapping("/gooderr2")
@ResponseBody
public Good test3(Good good) throws BizException {
if(good.getNum()==1){
int i=5/0;
}else if (good.getNum()==2){
String name=null;
name.equals("abc");
}else if(good.getNum()==3){
throw new BizException(301,"我看错你了");
}else if(good.getNum()==4){
throw new BizException(401,"我看错你了");
}
return good;
}
@RestControllerAdvice
public class MyRestContollerAvice {
@ExceptionHandler( Exception.class)
public Object error(Exception ex){
Map map = new HashMap();
map.put("code",1);
map.put("message",ex.getMessage());
return map;
}
}
创建统一返回值类:
@Data
public class ResponseDTO {
private int code;
private String message;
private Object data;
public static ResponseDTO success(Object data){
ResponseDTO dto=new ResponseDTO();
dto.setData(data);
return dto;
}
public static ResponseDTO error(int code,String msg){
ResponseDTO dto=new ResponseDTO();
dto.setCode(code);
dto.setMessage(msg);
return dto;
}
}
统一异常处理
@RestControllerAdvice
@Slf4j
public class MyResponseAdvice implements ResponseBodyAdvice
整体代码:
package com.by.advice;
@RestControllerAdvice
public class MyRestControllerAdvice implements ResponseBodyAdvice