用于添加标头的Spring MVC ResponseBodyAdvice指定返回类型

时间:2016-08-10 18:56:15

标签: spring spring-mvc jackson hateoas

我的Controller中有一个返回对象列表的方法。 此方法支持分页结果并将HttpHeaders.LINK添加到HttpHeader以支持分页可发现性。 我被迫添加这些行以获得支持。 我想也许ControllerAdvice或ResponseAdvice支持这样做。 我如何检查方法的返回?如果返回类型是QueryResult,那么将HttpHeader添加到那个?

@RequestMapping(value = "/list", method = RequestMethod.GET)
    public ResponseEntity<QueryResult<Personel>> search(
            SearchOption searchOption)  {
        QueryResult<Personel> list=ipersonelService.search();
        HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(list, "/api/personel");
        return new ResponseEntity<>(list, headers, HttpStatus.OK);
    } 

此类通过Paging类生成标头

public static HttpHeaders generatePaginationHttpHeaders(QueryResult page, String baseUrl)
    throws URISyntaxException {

    HttpHeaders headers = new HttpHeaders();
    headers.add("X-Total-Count", "" + page.getTotalElements());
    String link = "";
    if ((page.getPageNumber() + 1) < page.getTotalPages()) {
        link = "<" + generateUri(baseUrl, page.getPageNumber() + 1, page.getPageSize()) + ">; rel=\"next\",";
    }
    // prev link
    if ((page.getPageNumber()) > 0) {
        link += "<" + generateUri(baseUrl, page.getPageNumber() - 1, page.getPageSize()) + ">; rel=\"prev\",";
    }
    // last and first link
    int lastPage = 0;
    if (page.getTotalPages() > 0) {
        lastPage = page.getTotalPages() - 1;
    }
    link += "<" + generateUri(baseUrl, lastPage, page.getPageSize()) + ">; rel=\"last\",";
    link += "<" + generateUri(baseUrl, 0, page.getPageSize()) + ">; rel=\"first\"";
    headers.add(HttpHeaders.LINK, link);
    return headers;
}


private static String generateUri(String baseUrl, int page, int size) throws URISyntaxException {
        return UriComponentsBuilder.fromUriString(baseUrl).queryParam("page", page).queryParam("size", size).toUriString();
    }



public class QueryResult<T> {

    private int     pageNumber;
    private int     totalElements;
    private int     totalPages;
    private int     pageSize;

    @JsonProperty("rows")
    private List<T> items;

    public QueryResult() {

    }   

    public int getPageNumber() {
        return pageNumber;
    }

    public void setPageNumber(int pageNumber) {
        this.pageNumber = pageNumber;
    }

    public int getTotalElements() {
        return totalElements;
    }

    public void setTotalElements(int totalElements) {
        this.totalElements = totalElements;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public List<T> getItems() {
        return items;
    }

    public void setItems(List<T> items) {
        this.items = items;
    }

    public int getTotalPages() {
        if (this.getPageSize() > 0)
            return this.getTotalElements() / this.getPageSize();

        return 0;
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

}

我想写这样的方法并自动添加链接标题

@RequestMapping(value = "/list", method = RequestMethod.GET)
        public QueryResult<Personel> search(
                SearchOption searchOption)  {
            return ripersonelService.search();
        } 

搜索后我找到了这个解决方案

@ControllerAdvice
public class BaseController implements ResponseBodyAdvice<Object> {


    private final Logger logger = Logger.getLogger(BaseController.class);

    @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)  {
        if(body instanceof QueryResult){
            QueryResult result =(QueryResult) body;
            HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(result, request.getURI().getPath());
            response.getHeaders().add(HttpHeaders.LINK, headers.getFirst(HttpHeaders.LINK));
            response.getHeaders().add("X-Total-Count", headers.getFirst("X-Total-Count"));
        }

        return body;
    }
}

1 个答案:

答案 0 :(得分:5)

您可以使用ResponseBodyAdvice的实现(通常也使用@ControllerAdvice注释)。将使用响应正文和ServerHttpResponse调用您的实现的beforeBodyWrite方法。后者允许您访问响应标头,并允许您根据需要更新它们。