Spring自动添加'X-Total-Count'标题

时间:2017-06-05 18:30:36

标签: java spring rest http

我正在为我的网络应用程序使用'admin-on-rest'用户界面,它有下一个限制:

  

注意:jsonServer REST客户端希望API包含一个   响应GET_LIST调用的X-Total-Count标头。价值必须   是集合中的资源总数。这允许   admin-on-rest知道总共有多少页资源,   并建立分页控制。

我通过手动将X-Total-Count标头添加到我的列表返回REST端点来解决了这个问题,如下所示: response.addHeader("X-Total-Count", String.valueOf(outputList.size()));

但我想知道:如果有一些优雅的方式在Spring自动完成它?我的意思是当某个端点返回JSON-list时,自动添加此标头的值是否正确?

3 个答案:

答案 0 :(得分:6)

是的,有! (如果您使用的是4.1或更高版本的弹簧)。

它被称为ResponseBodyAdvice,它使您能够拦截调用(就在写入响应之前,并允许访问原始http响应)。

基本上你需要的是实现这样的控制器建议:

@ControllerAdvice
public class ResourceSizeAdvice implements ResponseBodyAdvice<Collection<?>> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        //Checks if this advice is applicable. 
        //In this case it applies to any endpoint which returns a collection.
        return Collection.class.isAssignableFrom(returnType.getParameterType()); 
    }

    @Override
    public Collection<?> beforeBodyWrite(Collection<?> body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        response.getHeaders().add("X-Total-Count", String.valueOf(body.size()));
        return body;
    }
}

答案 1 :(得分:3)

如果您不仅仅需要响应中元素的总数,而只需要PagingAndSortingRepository的相应JPA方法中的实体总数,您可以执行类似于对分页应用程序有用的操作: )

灵感来自Bohdan的回答(https://stackoverflow.com/a/44376133/986160

@ControllerAdvice
public class ResourceSizeAdvice implements ResponseBodyAdvice<Page<?>> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        //Checks if this advice is applicable.
        //In this case it applies to any endpoint which returns a page.
        return Page.class.isAssignableFrom(returnType.getParameterType());
    }

    @Override
    public Page<?> beforeBodyWrite(Page<?> page, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        serverHttpResponse.getHeaders().add("X-Total-Count",String.valueOf(page.getTotalElements()));
        return page;
    }

}

确保调用默认方法的Pageable版本,因此它会返回Page而不是List

repository.findAll(new PageRequest(0,100));

如果您不使用存储库,则必须执行两个查询: Select * from ...Select count(*) from ... 并返回一个Wrapper,其中包含结果列表的内容加上来自计数的总数的总和。然后,您可以更改@ControllerAdvice课程以期望Wrapper并从中获取总数并将其放入标题中

答案 2 :(得分:0)

因为您可以从Page获得总元素。所以我已经将标题添加到ResponseEntity

@GetMapping(value = POSTS, headers = "Accept=application/json")
public ResponseEntity<?> getListPost(@RequestParam(required = false, defaultValue = "0") Integer page, @RequestParam(required = false, defaultValue = "25") Integer size) {
    // Create pageable
    Pageable pageable = new PageRequest(page, size);
    Page<Post> pagePost = postService.getPagePost(pageable);

    HttpHeaders headers = new HttpHeaders() {
        {
            add("Access-Control-Expose-Headers", "Content-Range");
            add("Content-Range", String.valueOf(pagePost.getTotalElements()));
        }
    };
    //        return new ResponseEntity<>(new CommonResponseBody("OK", 200, postList), HttpStatus.OK);
    return new ResponseEntity<>(new CommonResponseBody("OK", 200, new LinkedHashMap() {
        {
            put("data", pagePost.getContent());
        }
    }), headers, HttpStatus.OK);
}

getPagePost是在存储库中使用Page findAll(可分页可分页)的服务方法。

注意:如果内容范围不适合,请将内容范围更改为X-Total-Count。