是否可以在 spring boot 中用一个@ExceptionHandler处理多个异常?

Is it possible to handle multiple exceptions with one @ExceptionHandler in spring boot?

提问人:brain-dot-isEmpty 提问时间:3/2/2023 最后编辑:Eritreanbrain-dot-isEmpty 更新时间:3/2/2023 访问量:1107

问:

我有这段代码,我应该在其中返回自定义的错误消息和错误代码。它工作正常,但问题是它非常冗余。我想知道是否可以用一个@ExceptionHandler处理所有这些自定义异常。

@ControllerAdvice
public class HandleExceptions {

    @ExceptionHandler(value = CustomException1.class)
    public ResponseEntity<Object> handleCustomException1(CustomException1 e) {
        HttpStatus status = HttpStatus.NOT_FOUND;
        DataResponse data = new DataResponse("custom status code for exception 1", e.getMessage());
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(ExceptionResponse, status);
    }
    
    @ExceptionHandler(value = CustomException2.class)
    public ResponseEntity<Object> handleCustomException2(CustomException2 e) {
        HttpStatus status = HttpStatus.NOT_FOUND;
        DataResponse data = new DataResponse("custom status code for exception 2", e.getMessage());
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(ExceptionResponse, status);
    }
    
    @ExceptionHandler(value = CustomException3.class)
    public ResponseEntity<Object> handleCustomException3(CustomException3 e) {
        HttpStatus status = HttpStatus.BAD_REQUEST;
        DataResponse data = new DataResponse("custom status code for exception 3", e.getMessage());
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(ExceptionResponse, status);
    }


public class ExceptionResponse {
    private final DataResponse data;
}

public class DataResponse {
    private String statusCode;
    private String message;
}

自定义错误类都如下所示:

public class CustomException extends RuntimeException{
    public CustomException(String message){         
        super(message);     
    }
}

响应的示例如下:

Data: {
 status: 1111,
 message: user not found 
} 
Java spring-boot 重构 冗余 异常处理程序

评论


答:

0赞 Surya Teja Chavali 3/2/2023 #1

您可以创建将泛型作为参数的单个方法,并使用语句检查异常的类型并相应地修改响应。RuntimeExceptionif/else

下面的方法检查异常的类型,并在 DataResponse 对象中设置相应的 HTTP 状态代码和错误消息。如果异常不是自定义异常之一,则返回一般错误消息和状态代码。

@ControllerAdvice
public class HandleExceptions {

    @ExceptionHandler(value = RuntimeException.class)
    public ResponseEntity<Object> handleCustomException(RuntimeException e) {
        HttpStatus status;
        DataResponse data;
        
        if (e instanceof CustomException1) {
            status = HttpStatus.NOT_FOUND;
            data = new DataResponse("custom status code for exception 1", e.getMessage());
        } else if (e instanceof CustomException2) {
            status = HttpStatus.NOT_FOUND;
            data = new DataResponse("custom status code for exception 2", e.getMessage());
        } else if (e instanceof CustomException3) {
            status = HttpStatus.BAD_REQUEST;
            data = new DataResponse("custom status code for exception 3", e.getMessage());
        } else {
            // Handle any other exceptions here
            status = HttpStatus.INTERNAL_SERVER_ERROR;
            data = new DataResponse("unknown error", e.getMessage());
        }
        
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(exceptionResponse, status);
    }
}

1赞 Z-100 3/2/2023 #2

Surya Teja Chavali 的方法肯定有效,但为了可读性,也可以做得更好 (?)。

保留多个方法,每个方法都接受不同的异常,以免在代码中引入巨大的 if-else 混乱。

然后只需添加一个“普通”私有方法,然后该方法接受为参数并处理所有内容Throwable

@ControllerAdvice
public class HandleExceptions {

    @ExceptionHandler(value = CustomException1.class)
    public ResponseEntity<Object> handleCustomException1(CustomException1 e) {
        DataResponse data = new DataResponse("custom status code for exception 1", e.getMessage());
        return handleCustomException2(e, data, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(value = CustomException2.class)
    public ResponseEntity<Object> handleCustomException2(CustomException2 e) {
        DataResponse data = new DataResponse("custom status code for exception 2", e.getMessage());
        return handleException(e, data, HttpStatus.NOT_FOUND);
    }

    private ResponseEntity<ExceptionResponse> handleException(Throwable t, DataResponse data, HttpStatus status) {
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(ExceptionResponse, status);
    }
}

你也无法用这种方法删除所有冗余,但它的可读性会更高一些。

0赞 Dinosaur-Guy 3/2/2023 #3

我认为在这种情况下,冗余并不是真正的问题。实际代码实际上并不相同 - 您有不同的状态代码和每个状态代码的不同消息。因此,我认为,通过尝试组合这些方法只是为了节省几行代码,从而降低代码的可读性。 您也可以使用 将 你的 移动到注释并删除包装器。这样一来,你就把样板从你的逻辑中移开了。但这更像是个人喜好。ResponseStatusResponseEntity@ResponseBody

@ExceptionHandler(value = CustomException1.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public ExceptionResponse handleCustomException1(CustomException1 e) {
    DataResponse data = new DataResponse("custom status code for exception 1", e.getMessage());
    return new ExceptionResponse(data);
}

使用代替时,您还可以删除注释。@RestControllerAdvice@ControllerAdvice@ResponseBody

0赞 Mar-Z 3/2/2023 #4

具有超级的 Alternativ 解决方案:

public class CustomException extends RuntimeException {
    private final HttpStatus httpStatus;
    private final String statusCode;
    public CustomException(HttpStatus httpStatus, String statusCode, String message) {
        super(message);
        this.httpStatus = httpStatus;
        this.statusCode = statusCode;
    }
}

public class CustomException1 extends CustomException {
    public CustomException1(String message) {
        super(HttpStatus.NOT_FOUND, "custom status code for exception 1", message);
    }
}
// ... similar for 2 and 3
@ControllerAdvice
public class HandleExceptions {
    @ExceptionHandler(value = CustomException.class)
    public ResponseEntity<Object> handleCustomException(CustomException e) {
        DataResponse data = new DataResponse(e.getStatusCode, e.getMessage());
        ExceptionResponse exceptionResponse = new ExceptionResponse(data);
        return new ResponseEntity<>(exceptionResponse, e.httpStatus);
    }
}