1
Spring Data 的 Page 接口进行数据分页返回了很多很多垃圾信息,

clipboard.png

实际上我只需要下面这些分页信息:

"total_elements": 5,
"total_pages": 3,
"page_number": 2,
"number_of_elements": 2
{
  "request_id": "0062f2bd-b9d8-4452-a10b-9e6e4d66d077",
  "code": "0",
  "message": "OK",
  "description": "",
  "data": {
    "content": [
      {
        "id": 7132,
        "uuid": "663307d9-cee4-438e-bbc8-eed4a364527a",
        "user_id": 5,
        "name": "小米激光电视",
        "level": 3,
        "created_at": 1524651291372
      },
      {
        "id": 6867,
        "uuid": "9e0059d8-eae4-470d-a773-67b1f6783c99",
        "user_id": 4,
        "name": "激光电视要用菲涅尔幕布才对",
        "level": 3,
        "created_at": 1524651226885
      }
    ],
    "pageable": {
      "sort": {
        "sorted": true,
        "unsorted": false
      },
      "offset": 2,
      "page_size": 2,
      "page_number": 1,
      "paged": true,
      "unpaged": false
    },
    "total_pages": 3,
    "last": false,
    "total_elements": 5,
    "size": 2,
    "number": 1,
    "number_of_elements": 2,
    "first": false,
    "sort": {
      "sorted": true,
      "unsorted": false
    }
  }
}
上面是 Spring Data Commons 的 Page 接口对数据库查询进行分页返回的数据.

Repository 的接口为:

Page<User> getChildrenByParentId(Pageable page, String parentId);

完整的 Repository:

@Repository
public interface UserRepository extends Neo4jRepository<User, UUID> {

    @Query(
        value = "MATCH (u:User)-[r:MANAGE_BY]->(p:User {uuid: {1}}) RETURN u",
        countQuery = "MATCH (u:User)-[r:MANAGE_BY]->(p:User {uuid: {1}}) RETURN COUNT(*)"
    )
    Page<User> getChildrenByParentId(Pageable page, String parentId);

    @Query(value = "MATCH (u:User) RETURN u", countQuery = "MATCH (u:User) RETURN COUNT(*)")
    Page<User> getUsers(Pageable page);

    Optional<User> findByUuid(UUID uuid);
}

我们看到返回了很多多余的, 重复的数据. 为了解决这个问题, 创建一个Pagination DTO(PageChunk)来包装一下分页数据. 这个类的作用很简单就是包含每一次分页的内容和分页元数据(搜索结果总数, 当前页号, 总页数, 当前页包含多少项)

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Getter
@Setter
public class PageChunk<T> {
    private List<T> content = new ArrayList<>();
    private long totalElements;
    private int totalPages;
    private int pageNumber;
    private int numberOfElements;
}

原来的控制器方法

@GetMapping(path = "/children/{id}")
public Mono<Response<Page<User>>> getChildren(
    @NotBlank @PathVariable String id,
    @RequestParam(required = false) Integer page
) throws ResourceNotFoundException {
    Sort sort = new Sort(Sort.Direction.DESC, "u.created_at");
    PageRequest request = PageRequest.of(page == null ? 0 : page, 2, sort);
    return Mono.just(userRepository.getChildrenByParentId(request, id))
        .map(Response::new);
}

修改后的控制器方法

@GetMapping(path = "/children/{id}")
public Mono<Response<PageChunk<User>>> getChildren(
    @NotBlank @PathVariable String id,
    @RequestParam(required = false) Integer page
) throws ResourceNotFoundException {
    Sort sort = new Sort(Sort.Direction.DESC, "u.created_at");
    PageRequest request = PageRequest.of(page == null ? 0 : page, 2, sort);
    return Mono.just(userRepository.getChildrenByParentId(request, id))
        .map(this::pageChunk)
        .map(Response::new);
}
private PageChunk<User> pageChunk(Page<User> page) {
    PageChunk<User> chunk = new PageChunk();
    chunk.setContent(page.getContent());
    chunk.setTotalPages(page.getTotalPages());
    chunk.setTotalElements(page.getTotalElements());
    chunk.setPageNumber(page.getPageable().getPageNumber() + 1);
    chunk.setNumberOfElements(page.getNumberOfElements());
    return chunk;

}
Web 控制器我采用了Webflux 来开发的, 因此使用了 Mono 对返回的对象进行包装, 其中还有一个自定义的Response对象, 它的作用是让我们的JSON应答有一个通用的格式.

Response 类的定义如下:

import lombok.Getter;
import lombok.Setter;

import java.util.UUID;

@Getter
@Setter
public class Response<T> {
    private String requestId;
    private String code = "";
    private String message = "";
    private String description = "";
    private Object data = "";

    public Response(T data, String code, String message) {
        this.requestId = UUID.randomUUID().toString();
        this.data = data;
        this.code = code;
        this.message = message;
    }

    /**
     * 正确结果
     *
     * @param data
     */
    public Response(T data) {
        this.requestId = UUID.randomUUID().toString();
        this.data = data;
        this.code = "0";
        this.message = "OK";
    }
}

然后是修改后的JSON响应结果

{
  "request_id": "8f381bfa-8ed9-442c-91fb-2678a33dee7f",
  "code": "0",
  "message": "OK",
  "description": "",
  "data": {
    "content": [
      {
        "id": 7132,
        "uuid": "663307d9-cee4-438e-bbc8-eed4a364527a",
        "user_id": 5,
        "name": "小米激光电视",
        "level": 3,
        "created_at": 1524651291372
      },
      {
        "id": 6867,
        "uuid": "9e0059d8-eae4-470d-a773-67b1f6783c99",
        "user_id": 4,
        "name": "激光电视要用菲涅尔幕布才对",
        "level": 3,
        "created_at": 1524651226885
      }
    ],
    "total_elements": 5,
    "total_pages": 3,
    "page_number": 2,
    "number_of_elements": 2
  }
}

看起来舒服多了!


developerworks
1.7k 声望266 粉丝