全局异常处理实战篇

注解ControllerAdvice配合ExceptionHandler实现全局异常处理。当将异常抛出时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。

  • 第一步,定义一个全局异常处理Hanlder
@ControllerAdvice
public class GlobalExceptionHanlder {
//  
//    @Autowired
//    private Tracer tracer;

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHanlder.class);
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = Throwable.class)
    @ResponseBody
    public RestResponse handler(HttpServletRequest req, Throwable throwable){
        LOGGER.error(throwable.getMessage(),throwable);
//      tracer.addTag(Span.SPAN_ERROR_TAG_NAME, ExceptionUtils.getExceptionMessage(throwable));
//      System.out.println(tracer.getCurrentSpan().getTraceId());
        RestCode restCode = Exception2CodeRepo.getCode(throwable);
        RestResponse response = new RestResponse(restCode.code,restCode.msg);
        return response;
    }
    
}
 
 
  • 第二步,定义异常类型转换返回代码类

public class Exception2CodeRepo {
    
    private static final ImmutableMap MAP = ImmutableMap.builder()
            .put(IllegalParamsException.Type.WRONG_PAGE_NUM,RestCode.WRONG_PAGE)
            .put(IllegalStateException.class,RestCode.UNKNOWN_ERROR)
            .put(UserException.Type.USER_NOT_LOGIN,RestCode.TOKEN_INVALID)
            .put(UserException.Type.USER_NOT_FOUND,RestCode.USER_NOT_EXIST)
            .put(UserException.Type.USER_AUTH_FAIL,RestCode.USER_NOT_EXIST).build();
    
    private static Object getType(Throwable throwable){
       try {
          return FieldUtils.readDeclaredField(throwable, "type", true);
       } catch (Exception e) {
          return null;
       }    
    }
    
    
    public static RestCode getCode(Throwable throwable) {
        if (throwable == null) {
            return RestCode.UNKNOWN_ERROR;
        }
        Object target = throwable;
        if (throwable instanceof WithTypeException) {
            Object type = getType(throwable);
            if (type != null ) {
                target = type;
            }
        }
        RestCode restCode =  MAP.get(target);
        if (restCode != null) {
            return restCode;
        }
        Throwable rootCause = ExceptionUtils.getRootCause(throwable);
        if (rootCause != null) {
            return getCode(rootCause);
        }
        return restCode.UNKNOWN_ERROR;
    }

}
  • 第三步,自定义异常类,继承RuntimeException
public class IllegalParamsException extends RuntimeException implements WithTypeException{
    private static final long serialVersionUID = 1L;
    private Type type;
    public IllegalParamsException(){
        
    }
    
    public IllegalParamsException(Type type,String msg){
        super(msg);
        this.type = type;
    }
    
    public Type type(){
        return type;
    }
    
    public enum Type{
        WRONG_PAGE_NUM,WRONG_TYPE
    }
}

public class UserException extends RuntimeException implements WithTypeException{
  
  private static final long serialVersionUID = 1L;

  private Type type;
  
  public UserException(String message) {
    super(message);
    this.type = Type.LACK_PARAMTER;
  }

  public UserException(Type type, String message) {
    super(message);
    this.type = type;
  }
  
  public  Type type(){
    return type;
  }

  
  public enum Type{
    WRONG_PAGE_NUM,LACK_PARAMTER,USER_NOT_LOGIN,USER_NOT_FOUND,USER_AUTH_FAIL;
  }

}

/**
 * 包含类型的异常
 */
public interface WithTypeException {

}
  • 第四步,定义返回值枚举类
public enum RestCode {
    OK(0,"ok"),
    UNKNOWN_ERROR(1,"未知异常"),
    TOKEN_INVALID(2,"TOKEN失效"),
    USER_NOT_EXIST(3,"用户不存在"),
    WRONG_PAGE(10100,"页码不合法"),
    LACK_PARAMS(10101,"缺少参数");
    
    public final int code;
    public final String msg;
    
    private RestCode(int code,String msg){
        this.code = code;
        this.msg = msg;
    }

}
  • 第五步,业务代码中异常抛出
public User getLoginedUserByToken(String token) {
    Map map = null;
    try {
      map = JwtHelper.verifyToken(token);
    } catch (Exception e) {
      throw new UserException(Type.USER_NOT_LOGIN,"User not login");
    }
    String email =  map.get("email");
    Long expired = redisTemplate.getExpire(email);
    if (expired > 0L) {
      renewToken(token, email);
      User user = getUserByEmail(email);
      user.setToken(token);
      return user;
    }
    throw new UserException(Type.USER_NOT_LOGIN,"user not login");
    
  }

结果:{"code":2,"msg":"TOKEN失效","result":null}

你可能感兴趣的:(全局异常处理实战篇)