springboot为什么需要全局异常处理器
全局异常处理器,就是把整个系统的异常统一自动处理,程序员不用再写try...catch
为什么需要全局异常呢?
不用强制写try-catch,由全局异常处理器,统一捕获处理
如果不用try-catch捕获的话,客户端就会怎么样?
一般程序员的try-catch
这种格式对于客户端来说很不友好,而一啊不能的程序员就是try-catch
还有一种自动化处理的,就是不用写try-catch,由全局异常处理器来处理
自定义异常,只能用全局异常来捕获
自定义异常那么写客户端也看不懂
编码实现一个springboot全局异常处理器
封装异常内容,统一存储在枚举类中
封装Controller的异常结果
ErrorResult
package com.example.demo.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.bytebuddy.implementation.bytecode.Throw;
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ErrorResult {
//异常状态码
private Integer status;
//异常信息
private String msg;
//异常的名字
private String exception;
//对异常提示语进行封装
public static ErrorResult fail(ResultCode resultCode, Throwable e, String
message){
ErrorResult result = ErrorResult.fail(resultCode,e);
result.setMsg(message);
return result;
}
public static ErrorResult fail(ResultCode resultCode,Throwable e){
ErrorResult result = new ErrorResult();
result.setMsg(resultCode.message());
result.setStatus(resultCode.code());
result.setException(e.getClass().getName());
return result;
}
}
有handleThrowable捕获运行时异常,并把异常统一封装为ErrorResult对象
再加一个全局异常处理器
增强Controller的扩展功能,而全局异常处理器,就是扩展功能之一
@ExceptionHandler统一处理某一类异常,从而能减少代码重复率和复杂度
@ResponseStatus指定客户端收到的http状态码,这里配置500错误,客户端就显示500错误
package com.example.demo.exceptions;
import com.example.demo.response.ErrorResult;
import com.example.demo.response.ResultCode;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.Throw;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Throwable.class)
public ErrorResult handleThrowable(Throwable e, HttpServletRequest request){
ErrorResult error = ErrorResult.fail(ResultCode.SYSTEM_ERROR,e);
log.error("URL:{},系统异常",request.getRequestURI(),e);
return error;
}
}
在throw的异常,不会显示提示信息,需要自定义异常
@GetMapping("/error1")
public void error1(){
int i = 9/0;
}
这样就会友好显示异常信息
自定义异常不会报提示信息
把自定义异常集成进全局异常处理器
步骤1:封装一个自定义异常
自定义异常继承RuntimeException
自定义异常通常是集成了RuntimeException
就两个保护属性,一个赋值构造函数ResultCode
步骤2,把自定义异常集成进全局异常处理器
package com.example.demo.exceptions;
import com.example.demo.response.ResultCode;
import io.swagger.models.auth.In;
public class BusinessException extends RuntimeException{
protected Integer code;
protected String msg;
public BusinessException(ResultCode resultCode){
this.code = resultCode.code();
this.msg = resultCode.message();
}
}
@ExceptionHandler(BusinessException.class)
public ErrorResult handleBusinessException(BusinessException e,HttpServletRequest request){
ErrorResult error = ErrorResult.builder().status(e.code)
.msg(e.msg).exception(e.getClass().getName()).build();
log.warn("URL:{} 业务异常",request.getRequestURI(),error);
return error;
}
@GetMapping("/error2")
public void error2(){
throw new BusinessException(ResultCode.USER_NOT_FOUND);
}
全局异常处理器,只有在上节课的基础上,添加一个自定义异常处理即可
即在GlobalExceptionHandler加入自定义异常处理器
@ExceptionHandler(BusinessException.class)集成进全局异常处理器
处理自定义异常
步骤3,体验效果
抛出自定义的异常类
把全局异常处理器,集成进接口返回值统一标准格式
把全局异常处理器的Json格式转化为接口返回值统一标准格式
如果你给客户端两种格式,正常用一种,异常用一种,你会被客户端的同学骂死,客户端必须统一
那么怎么改呢?
步骤1:改造responseHandler即@ControllerAdvice注解的类,改造这个类
异常统一标准格式,以前的异常是
status
message
exception
现在的异常是
status
desc
data
加上
if(o instanceof ErrorResult){
ErrorResult errorResult = (ErrorResult) o;
return Result.fail(errorResult.getStatus(),errorResult.getMsg());
}
这样的一句代码即可