Глобальная обработка исключений SpringBoot

Spring Boot

Анализ проблем обработки исключений

Как обрабатывать исключения

введение проблемы

  • Для исключений кода есть два обычных метода обработки для прямого броска бросков и еще один захват try..catch.

  • В java-проекте могут быть искусственные логические исключения, и второй метод обработки может быть принят для получения сведений об исключении или для обеспечения того, чтобы программа продолжала выполняться вниз при возникновении исключения.

  • Однако перехват каждого исключения в коде сделает код избыточным и не будет способствовать обслуживанию.

Решения

  • Определите глобальный класс обработки исключений для возврата унифицированной и стандартизированной информации об исключениях;

  • Логика обработки заключается в том, чтобы сначала определить, произойдет ли исключение, а затем выполнить последующую конкретную операцию.

бизнес-пример

В этой статье в основном реализована логика глобальной аномальной обработки, только простой бизнес

Департамент компании должен добавить сотрудников. Поток обработки: 1. Во-первых, запрашивает объект сотрудника в соответствии с номером сотрудника. 2. Определите, имеет ли объект сотрудника информацию, то есть ли не пусто. 3. Если есть Информация, это означает, что она уже существует, и не нужно его добавлять. Если нет, добавляется напрямую.

код показывает, как показано ниже:

public class MyService {
    // 注入dao层
    @Autowired
    EmployeeecMapper employeeecMapper;

    /**
     * 添加员工信息
     * @param employee 员工对象
     * @return 影响的行数
     */
    public int add(Employee employee) {
        // 根据id查询员工对象
        Employeeec emp = employeeecMapper.selectByPrimaryKey(employee.getId());
        // 判断是否已有该员工
        if (emp != null){
            // 已有,抛出异常,异常信息为已有该员工
            throw new RuntimeException("异常代码:1201,错误信息:该员工已存在");
        }
        // 没有,插入该员工
        return employeeecMapper.insert(emp);
    }
}

Процесс обработки исключений

В бизнесе существуют исключения времени выполнения и исключения бизнес-логики.Первые трудно обнаружить, когда они не запущены, а вторые можно определить, когда они распространяются по всему бизнесу.Поэтому исключения делятся на непредсказуемые исключения и известные исключения. Процесс выглядит следующим образом:

  1. Настройте глобальный класс исключений, используйте@ControllerAdvice, усовершенствования контроллера
  2. Настройте код ошибки и сообщение об ошибке. Два исключения в конечном итоге будут представлены в едином формате информации, код ошибки + сообщение об ошибке.
  3. Для предсказуемых исключений, которые активно создаются программистом в коде,SpringMVCЕдиный захват.
  4. Непредсказуемые исключения обычно возникают из-за ошибок в системе или некоторых внешних факторов (таких как колебания сети, простои сервера и т. д.).RuntimeExceptionТип (исключение во время выполнения).

Известное исключение

Определите класс информации об исключении, переменные - это код ошибки и информация об ошибке, при перехвате пользовательского исключения возвращайте объект напрямую

Непредвиденное необычное

Определите карту, храните общие исключения в нем и определите коды ошибок. Для других необычных исключений, то есть те, которые не на карте, один и тот же объект исключения может быть возвращен.

Поток кода обработки исключений

Известное исключение

1. Определите интерфейс для печати информации об исключении и возврата результатов.

public interface ResultCode {
    // 操作是否成功
    boolean success();

    // 操作结果代码
    long code();

    // 提示信息
    String message();
}
public interface Response {
    public static final boolean SUCCESS = true;
    public static final int SUCCESS_CODE = 10000;
}

2. Определите класс перечисления и возвращайте класс результата для печати информации об исключении.

@ToString
public enum  CommonCode implements ResultCode {
    NO_PAGE(false,404,"没有信息"),
    FAIL(false,500,"操作失败!"),
    SUCCESS(true,200,"操作成功!");

    // 结果信息
    boolean success;
    long code;
    String message;
    
    // 带参构造
    CommonCode(boolean success, long code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }

    @Override
    public boolean success() {
        return true;
    }

    @Override
    public long code() {
        return code;
    }

    @Override
    public String message() {
        return message;
    }
}
@Data
@ToString
public class ResponseResult implements Response {

    boolean success = SUCCESS;

    long code = SUCCESS_CODE;

    String message;

    public ResponseResult(ResultCode resultCode){
        this.success = resultCode.success();
        this.code = resultCode.code();
        this.message = resultCode.message();
    }
}

3. Определите класс исключений ошибок

public class CustomException extends RuntimeException{

    @Autowired
    ResultCode resultCode;
    
    // 带参构造
    public CustomException(ResultCode resultCode){
        this.resultCode = resultCode;
    }
    
    // getter
    public ResultCode getResultCode(){
        return resultCode;
    }
}

4. Определите класс генерации исключений

public class ExceptionCast {

    // 静态方法
    public static void cast(ResultCode resultCode){
        throw new CustomException(resultCode);
    }
}

5. Определите класс перехвата исключений, используйтеControllerAdviceРасширенные контроллером аннотации и дополнительные методы, перехватывающие исключения CustomException.ExceptionHandlerАннотация, вы можете перехватывать все исключения этого класса и возвращать данные json.

@ControllerAdvice 
public class ExceptionCatch {

    /**
     * 捕获CustomException类异常
     * @param customException
     * @return 结果信息,json数据
     */
    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult customException(CustomException customException){
        ResultCode resultCode = customException.getResultCode();
        return new ResponseResult(resultCode);
    }
}

6. Исключения в бизнесе

public class MyService {

    @Autowired
    EmployeeecMapper employeeecMapper;

    public int add(Employee employee) {
        Employeeec emp = employeeecMapper.selectByPrimaryKey(employee.getId());
        if (emp != null){
            ExceptionCast.cast(CommonCode.FAIL);
        }
        return employeeecMapper.insert(emp);
    }
}

Независимая обработка исключений

1. Как и в случае с известным исключением, сначала добавьте код ошибки в класс CommonCode, например

UNAUTHORISE(false,510,"没有权限"),

2. Добавление метода аномального захвата в класс аномального захвата. В этом методе определите сопоставление кода ошибки типа исключения хранилища MAP только для чтения, элементы на карте, унифицированное использование кода ошибки 999.

UNKNOWNERROR(false,999,"未知异常"),
@ControllerAdvice
public class ExceptionCatch {

    // 定义map,存贮常见错误信息。该类map不可修改
    private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;
    // 构建ImmutableMap
    protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();

    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseResult customException(CustomException customException){
        ResultCode resultCode = customException.getResultCode();
        return new ResponseResult(resultCode);
    }

    /**
     * 捕获非自定义类异常
     * @param exception
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult exception(Exception exception){
        // 记录日志
        LOGGER.error("catch exception ==> ",exception.getMessage());
        if (EXCEPTIONS == null){
            EXCEPTIONS = builder.build();
        }
        ResultCode resultCode = EXCEPTIONS.get(exception.getClass());
        if (resultCode != null){
            return new ResponseResult(resultCode);
        }else {
            return new ResponseResult(CommonCode.UNKNOWNERROR);
        }
    }

    static {
        builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM);
    }
}

готово~~