springboot处理异常的5种方式
程序的异常:Throwable
严重错误问题:Error 我们不处理。这种问题一般都是很严重的,我们一般处理不了,比如说内存溢出。
问题:Exception
1.运行期问题:RuntimeException 这种问题我们也不处理,因为是你写代码的问题,而且这个问题的出现肯定是我们的代码不够严谨,需要修正代码的。
2.编译期问题:不是RuntimeException的异常 必须进行处理的,因为你不处理,编译就不能通过。
如果程序出现了问题,我们没有做任何处理,最终JVM会做出默认的处理。
1.把异常的名称、原因及出现的位置等信息输出在控制台。
2.同时会结束程序。
(但是呢,其余没有问题的程序就不能继续执行了)
所以感觉JVM的默认处理不够好,既然不好那我们就自己来处理呗。
1、自定义错误页面
SpringBoot默认的异常处理机制:springboot默认提供了一套处理异常的机制。一旦程序出现了异常,SpringBoot会向/error的url发送请求。在springboot中提供了一个叫BasicErrorController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。 如 果 我 们 需 要 将 所 有 的 异 常 统一 跳 转 到 自 定 义 的 错 误 页 面 , 需 要 再 src/main/resources/templates 目录下创建 error.html 页面。注意:名称必须叫 error
还可以在src/main/resources/templates/error目录下编写状态码.html文件,会默认先从这里找,找不到再找src/main/resources/templates下的error.html
2、@ExceptionHandle 注解处理异常
上一种方法不管发生什么异常,都只能跳转到一个页面,颗粒度太大,这一种方式可以实现对不同的异常做不同的处理。
@RequestMapping
@Controller
public class ExceptionController {
@PostMapping("/exception")
public String hello(){
return "index";
}
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e);
mv.setViewName("error");
return mv;
}
}
优点:可以自定义存储异常信息的key,和跳转视图的名称。
缺点:需要编写大量的异常方法,不能跨controller,如果两个controller中出现同样的异常,需要重新编写异常处理方法。
3、@ControllerAdvice+@ExceptionHandler 注解处理异常
上一种方式必须要在每一个Controler里面重复写异常处理代码,代码复用性太差,这一种方法可以实现异常的全局处理。需要创建一个能够处理异常的全局异常类。在该类上需要添加@ControllerAdvice 注解
@ControllerAdvice
public class GlobalController {
@ExceptionHandler(value = {java.lang.ArithmeticException.class})
public ModelAndView arithmeticExceptionHandler(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e+"controllerAdvice");
mv.setViewName("error");
return mv;
}
}
缺点:编写大量的异常处理方法,代码冗余。
4、配置 SimpleMappingExceptionResolver 处理异常
上一种方式,每处理一种异常就要写一个处理方法,如果有很多异常需要处理,写起来会很麻烦,这一种方式可以很好的解决这种问题,需要在全局异常类中添加一个方法完成异常的统一处理。
@Configuration
public class GlobalException {
@Bean
public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException","error");
prop.setProperty("java.lang.NullPointerException","error");
resolver.setExceptionMappings(prop);
return resolver;
}
}
缺点:不显示具体异常信息
5、自定义 HandlerExceptionResolver 类处理异常
上一种方式不能在跳转页面的同时携带异常信息,这样不利于排错,当前这种方式可以解决上述问题,我们需 要 在全局异常处理类中实现HandlerExceptionResolver 接口。
@Configuration
public class GlobalException implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView();
if(ex instanceof ArithmeticException){
mv.setViewName("error");
}
if(ex instanceof NullPointerException){
mv.setViewName("error");
}
mv.addObject("errorMsg",ex.toString());
return mv;
}
}
通用异常处理:
1、自定义异常枚举类
public enum ExceptionEnum {
PRICE_CANNOT_BE_NULL(500,"商品价格不能为空"),
;
private int code;
private String msg;
ExceptionEnum() {
}
ExceptionEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
2、自定义异常类
public class MyException extends RuntimeException{
private ExceptionEnum exceptionEnum;
public MyException() {
}
public MyException(ExceptionEnum exceptionEnum) {
this.exceptionEnum = exceptionEnum;
}
public ExceptionEnum getExceptionEnum() {
return exceptionEnum;
}
public void setExceptionEnum(ExceptionEnum exceptionEnum) {
this.exceptionEnum = exceptionEnum;
}
@Override
public String toString() {
return "MyException{" +
"exceptionEnum=" + exceptionEnum +
'}';
}
}
3、自定义异常结果处理类
public class ResultException {
private Integer statusCode;
private String message;
private Long timeStamp;
public ResultException() {
}
public ResultException(ExceptionEnum em){
this.statusCode = em.getCode();
this.message = em.getMsg();
this.timeStamp = System.currentTimeMillis();
}
public Integer getStatusCode() {
return statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Long getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Long timeStamp) {
this.timeStamp = timeStamp;
}
@Override
public String toString() {
return "ResultException{" +
"statusCode=" + statusCode +
", message='" + message + '\'' +
", timeStamp=" + timeStamp +
'}';
}
}
4、全局异常处理
@ControllerAdvice
public class GlobalException {
@ExceptionHandler(MyException.class)
public ResponseEntity<ResultException> handlerRuntimeException(MyException e){
ExceptionEnum exceptionEnum = e.getExceptionEnum();
return ResponseEntity.status(exceptionEnum.getCode()).body(new ResultException(exceptionEnum));
}
}
|