使用@ExceptionHandler根据请求动态返回HTTP状态代码

我想根据响应对象错误动态返回HTTPStatus代码,如400,400,404等 . 我被提到这个问题 - Programmatically change http response status using spring 3 restful但它没有帮助 .

我有一个带有 @ExceptionHandler 方法的Controller类

@ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseEntity<?> handleException(CustomException e) {
        return new ResponseEntity<MyErrorResponse>(
                new MyErrorResponse(e.getCode(), ExceptionUtility.getMessage(e.getMessage())), 
                ExceptionUtility.getHttpCode(e.getCode()));
    }

ExceptionUtility 是一个类,我有上面使用的两个方法( getMessagegetCode ) .

public class ExceptionUtility {
    public static String getMessage(String message) {
        return message;
    }

    public static HttpStatus getHttpCode(String code) {
        return HttpStatus.NOT_FOUND; //how to return status code dynamically here ?
    }
}

我不想检查条件并相应地返回响应代码,还有其他更好的方法吗?

回答(2)

2 years ago

您需要为不同的Exception定义不同的Exception处理程序,然后使用 @ResponseStatus ,如下所示:

@ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler({ UnAuthorizedException.class })
    public @ResponseBody ExceptionResponse unAuthorizedRequestException(final Exception exception) {

        return response;
    }

@ResponseStatus(HttpStatus.CONFLICT)
    @ExceptionHandler({ DuplicateDataException.class })
    public @ResponseBody ExceptionResponse DuplicateDataRequestException(final Exception exception) {

        return response;
    }

@ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ InvalidException.class })
    public @ResponseBody ExceptionResponse handleInvalidException(final Exception exception) {

        return response;
    }

这里的例子是 InvalidException.classDuplicateDataException.class 等 . 您可以定义自定义异常并从控制器层抛出它们 . 例如,您可以定义 UserAlreadyExistsException 并从异常处理程序返回 HttpStatus.CONFLICT 错误代码 .

2 years ago

您的 @ExceptionHandler 方法需要两件事:(i)有一个 HttpServletResponse 参数,以便您可以设置响应状态代码; (ii)没有 @ResponseStatus 注释 .

@ExceptionHandler(CustomException.class)
@ResponseBody
public ResponseEntity<?> handleException(HttpServletResponse resp, CustomException e) {
    resp.setStatus(ExceptionUtility.getHttpCode(e.getCode()).value());
    return new ResponseEntity<MyErrorResponse>(
            new MyErrorResponse(e.getCode(), ExceptionUtility.getMessage(e.getMessage())),
            ExceptionUtility.getHttpCode(e.getCode()));
}

我已经使用这种 @ExceptionHandler 来处理 NestedServletException ,这是一个例外,Spring有时会创建它来包装需要处理的"actual"异常(下面的代码) . 请注意,如果需要, @ExceptionHandler 方法可以同时将请求和响应对象作为参数 .

@ExceptionHandler(NestedServletException.class)
@ResponseBody
public Object handleNestedServletException(HttpServletRequest req, HttpServletResponse resp, 
        NestedServletException ex) {
    Throwable cause = ex.getCause();
    if (cause instanceof MyBusinessLogicException) {
        resp.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
        return createStructureForMyBusinessLogicException((MyBusinessLogicException) cause);
    }
    if (cause instanceof AuthenticationException) {
        resp.setStatus(HttpStatus.UNAUTHORIZED.value());
    } else if (cause instanceof AccessDeniedException) {
        resp.setStatus(HttpStatus.FORBIDDEN.value());
    } else {
        resp.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
    return createStructureForOtherErrors(req, cause.getMessage(), resp.getStatus());
}