Spring auto-add header "X-Total-Count"

I am using an "admin-on-rest" user interface for my web application and has the following limitation:

Note. The jsonServer REST client expects the API to include the X-Total-Count Header in response to GET_LIST calls. The value should be the total number of resources in the collection. This allows admin-on-rest to find out how many resource pages there are in total, and create pagination controls.

I solved the problem by manually adding the X-Total-Count header to my list-returning REST endpoints as follows: response.addHeader("X-Total-Count", String.valueOf(outputList.size()));

But I'm wondering: If there is an elegant way to do this automatically in Spring? I mean automatically adding this header with the correct value when some endpoint returns a JSON list?

+3


source to share


3 answers


Yes there is! (If you are using spring 4.1 or higher).

It's called ResponseBodyAdvice and allows you to intercept calls (just before the response is written and gives you access to the raw HTTP response).



Basically, you need to implement a controller tip like this:

@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;
    }
}

      

+4


source


If you don't just want the total number of items in the response, but the total number of objects in the corresponding JPA method PagingAndSortingRepository

, you can do something like this which is useful for swap applications :)

Inspired by Bogdan ( fooobar.com/questions/2414160 / ... )

@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;
    }

}

      



Make sure you call the default version of the default ones like this: Page

rather than List

:

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

      

If you are not using repos, you need to run two queries: Select * from ...

and Select count(*) from ...

and return a Wrapper

which has the content for the list of results plus the total for the total coming from the invoice. Then you can change the class @ControllerAdvice

to expect yours Wrapper

and get the total from it and put it in the header

+3


source


From behind the page, you can get total items. So I added headers to the 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 is a service method that uses the findAll page (accessible page) in the repository.

Note. Change Content-Range to X-Total-Count if it doesn't work for you.

0


source







All Articles