前言:
spring boot学习以及使用也有一段时间了,平时疏于整理资料,故今日写一篇关于全局异常的资料
背景:
异常处理是为了给用户带来良好的交互体验
异常:
- 访问了错误的页面,或者是非法的访问导致服务器不能返回正常的数据,例如访问了不存在的页面导致404
- 程序代码内部的错误,在开发时期由于没有考虑周全导致的程序异常,列如常见的空指针异常(NullPointException
操作:
关于第一种处理:
可以定义一个ErrorController来进行全局的处理,如果404则会跳转到404.html页面,这种处理会根据statusCode返回相对应的页面,当然这里也可以设置返回成json的数据格式,只要在方法上加上@ResponseBody,然后修改返回值即可.
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
class MainsiteErrorController implements ErrorController {
@RequestMapping("/error")
public String handleError(HttpServletRequest request) {
System.out.println("成功拦截异常信息");
//获取statusCode:401,404,500
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == 401) {
return "/error.html";
} else if (statusCode == 404) {
return "/404.html";
} else if (statusCode == 403) {
return "/error.html";
} else if (statusCode == 500) {
return "/error.html";
} else {
return "/error.html";
}
}
@Override
public String getErrorPath() {
return "/error";
}
}
关于第二种处理:
可以定义一个GlobalExceptionHandler全局异常处理类,在类上加@ControllerAdvice异常拦截注解,在方法上面加入@ExceptionHandler(对应的异常类.class)注解,这种方法可以是多个的,Exception是全局的异常处理,如果有ArithmeticException的异常则会优先跳入对应的ArithmeticException处理方法中,则不会进入Exception处理方法中,
import com.example.advanced.result.ResponseCode;
import com.example.advanced.result.ServerResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
private String ArithmeticException(HttpServletRequest request, Exception e) {
System.out.println("ArithmeticException成功拦截");
return "/error.html";
}
@ExceptionHandler(Exception.class)
@ResponseBody
private ServerResponse<Object> handlerErrorInfo(HttpServletRequest request, Exception e) {
System.out.println("GlobalException成功拦截");
log.error("{} Exception", request.getRequestURI(), e);
if (e instanceof BusinessException) {
return ServerResponse.createByErrorCodeMessage(((BusinessException) e).getCode(), e.getMessage());
} else {
return ServerResponse.createByErrorMessage("服务器异常,请联系管理员处理");
}
}
}
值得一提的是我们可以自定义一些异常,列如上述代码中的BusinessException就是业务异常,通过继承RuntimeException类,然后对于一些可能会发生逻辑错误的异常进行手动抛出,然后让全局异常进行判断,[e instanceof BusinessException]这一块内容,如果是业务逻辑异常,则对其进行相对应的处理.
import com.example.advanced.result.ResponseCode;
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException(ResponseCode responseCode) {
super(responseCode.getDesc());
this.code = responseCode.getCode();
}
public BusinessException(ResponseCode responseCode, String message) {
super(message);
this.code = responseCode.getCode();
}
//省略get,set
}
总结:
运行时异常返回的状态码是500,但是会优先被GlobalExceptionHandler拦截,而对应的异常像上文中ArithmeticException(例如int i = 1/0)除数不能为0的异常,会优先被ArithmeticException()这个方法所捕获.
总的来说异常执行顺序是 ArithmeticException>Exception>errorController