使用@ExceptionHandler动态返回HTTP状态码

7
我希望您能动态返回HTTP状态码,例如400、400、404等,根据响应对象错误。我被引用到这个问题-Programmatically change http response status using spring 3 restful,但它没有帮助我。
我有一个控制器类,其中包含一个@ExceptionHandler方法。
@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 ?
    }
}

我不想检查条件并根据响应代码返回结果,有没有其他更好的方法来做到这一点?

3个回答

5

第一种方法:

你可以在你的自定义异常类中使用HTTPStatus字段,例如:

    class CustomException {
         HttpStatus httpStatus;
         ....other fields
    }

您可以像以下这样抛出错误:

throw new CustomException(otherField , HttpStatus.CREATED);

在您的异常处理程序中,您可以这样做:
@ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseEntity<?> handleException(CustomException e) {
        return new ResponseEntity<MyErrorResponse>(
                new MyErrorResponse(e.getCode(), ExceptionUtility.getMessage(e.getMessage())), 
                e.getHttpStatus());
    }

其中,e.getHttpStatus() 返回 HTTPStatus

第二种方法:

或者您可以为您的代码声明枚举,如下所示:

public enum ErrorCode {


    MyErrorCode(HttpStatus.OK);

    HttpStatus status;

//getter for httpstatus
}

然后您可以修改异常处理程序以

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

这里再次提到e.getHttpStatus()是在枚举类型上进行的方法调用,但为此您需要在自定义异常中更改代码字段类型。如果您不想做这个操作,可以在枚举中编写一个辅助方法,类似于:

HttpStatus getHttpStatus(String code) {
   return ErrorCode.valueOf(code.toUpperCase()).getHttpStatus();
}

抱歉,我错过了上面方法中的空指针异常,但您可以根据需要进行修改,这只是一个想法。 :)

3
你的@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有时会创建的用于包装需要处理的“实际”异常的异常(下面是代码)。请注意,如果需要,@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());
}

1

您需要为不同的异常定义不同的异常处理程序,然后按如下方式使用@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 错误代码。

有没有更好的方法? - user2340345
这就是Spring异常处理程序的工作方式。如果您正在使用Spring,可以选择使用它。 - Suraj
请在您对答案进行负评时注明原因。 - Suraj
3
@Suraj 这是处理异常的基本方法。在这种情况下,状态码是“静态”设置的,而不是根据异常类中的信息“动态”设置的。 - Paulo Merson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接