springboot处理异常
Linging_24 人气:0程序的异常: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(){ //int i = 1/0; return "index"; } /** * 该方法返回ModelAndView:目的是为了可以让我们封装视图和错误信息 * @param e 参数 Exception e:会将产生异常对象注入到方法中 * @return */ @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 { /** * 该方法返回ModelAndView:目的是为了可以让我们封装视图和错误信息 * @param e 参数 Exception e:会将产生异常对象注入到方法中 * @return */ //拦截的异常可以写Exception @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 处理异常
上一种方式,每处理一种异常就要写一个处理方法,如果有很多异常需要处理,写起来会很麻烦,这一种方式可以很好的解决这种问题,需要在全局异常类中添加一个方法完成异常的统一处理。
/** * 通过 SimpleMappingExceptionResolver 做全局异常处理 */ @Configuration public class GlobalException { /** * 该方法必须要有返回值。返回值类型必须是: SimpleMappingExceptionResolver * @return */ @Bean public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){ SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties prop = new Properties(); //参数1:异常的全类名 参数2:视图的名字 prop.setProperty("java.lang.ArithmeticException","error"); prop.setProperty("java.lang.NullPointerException","error"); //设置异常与视图的映射信息 resolver.setExceptionMappings(prop); return resolver; } }
缺点:不显示具体异常信息
5、自定义 HandlerExceptionResolver 类处理异常
上一种方式不能在跳转页面的同时携带异常信息,这样不利于排错,当前这种方式可以解决上述问题,我们需 要 在全局异常处理类中实现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、自定义异常类
/** * 自定义异常类,继承RuntimeException */ 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 + @ExceptionHandler +自定义异常 来做全局异常处理 */ @ControllerAdvice public class GlobalException { /** * 拦截自定义异常MyException * @param e * @return */ // @ExceptionHandler(MyException.class) // public @ResponseBody ResultException handlerRuntimeException(MyException e){ // ExceptionEnum exceptionEnum = e.getExceptionEnum(); // ResultException res = new ResultException(exceptionEnum); //
加载全部内容