在ControllerAdvice中获取returnValue

时间:2018-10-11 22:03:46

标签: java spring spring-boot spring-restcontroller

我刚刚在我的Spring Boot应用程序中创建了一个controlleradvice,并试图在该建议中获取返回值对象:

            @ControllerAdvice
        public class ResponseAdvice implements ResponseBodyAdvice<Object> {


            @Override
            public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
                return true;
            }

            @Override
            public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                          Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                          ServerHttpRequest request, ServerHttpResponse response) {

                    response.setStatusCode(HttpStatus.OK);
                    int status = <from returnValue>;
                    return ResponseEntity.status(HttpStatus.valueOf(status)).body(body);

            }
        }

以及在我的控制器中:

return new ResponseEntity(HttpStatus.NO_CONTENT);

这里的逻辑总是发送200个状态代码,但是在响应中我们有实际的状态代码:

{
    "headers": {},
    "body": {},
    "statusCode": "NO_CONTENT",
    "statusCodeValue": 201
}

所以我的问题是我不知道如何使用returnType访问beforeBodyWrite方法中的returnValue。 在IDE中调试时,可以看到returnValue已添加到returnType。

2 个答案:

答案 0 :(得分:1)

根据您的问题,我假设您需要控制器始终发送200,并将实际的主体,标头,状态代码包装在一个对象中并作为响应发送。

这是解决问题的方法

有一个自定义对象来包装您的回复

public class MyResponse {
    Map<String, String> headers;
    Object body;
    String statusCode;
    int statusCodeValue;

    public MyResponse(Map<String, String> headers, Object body, String statusCode, int statusCodeValue) {
        this.headers = headers;
        this.body = body;
        this.statusCode = statusCode;
        this.statusCodeValue = statusCodeValue;
    }
}

只需从您的控制器创建并返回包装器对象

@GetMapping("/user")
public MyResponse getUsers() {
    int statusValue = 200;
    List<User> users;
    try {
        users = service.getUser();
    }
    catch (UserNotFoundException ex) { statusValue = 404; }
    catch (ActionNotAllowedException ex) { statusValue = 401; }
    catch (Exception ex) { statusValue = 500;}

    return new MyResponse(getHeaders(), users, statusValue, HttpStatus.valueOf(statusValue))
}

答案 1 :(得分:0)

编辑:刚刚测试过。效果很好!

不是使用returnType,而是使用响应来获取状态,该状态由调用建议的控制器方法传播。我将您的beforeBodyWrite重写为仅用于获取和设置状态的部分。这次我还没有测试过,但是请记住在另一个实例上进行测试。

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      java.lang.Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
      ServerHttpResponse response) {
    int status = HttpStatus.OK.value();
    if (response instanceof ServletServerHttpResponse) {
      status = ((ServletServerHttpResponse) response).getServletResponse().getStatus();
    }
    response.setStatusCode(HttpStatus.OK);
    return ResponseEntity.status(HttpStatus.valueOf(status)).body(body);
}