Java泛型:分页 API 响应 – JUGBD


今天,我将分享一个真实的场景,在这个场景中,我能够将 Java 泛型用于真实的用例。我的任务是创建一个门户网站,假设它是一个学生门户网站。没什么特别的,只是一些 CRUD。所以当我在做的时候,我发现了一些模式。使用这些模式,我能够减少类的数量。我还将分享我应用的每项改进背后的思考过程。

首先,我将创建一个 api 来访问学生列表。分页是有道理的。因为可能有成千上万的学生,将他们全部显示在一起,不仅会给服务器和浏览器造成不必要的负担,而且对用户来说也很困难。

当然,我们可以向 JPA 发送一个 Pageable 请求,然后获取一个 Page 对象,其中包含大量学生和一些其他必要的数据,如项目总数、当前页面等。是的,您可以通过控制器从您的服务返回该对象,但是您的前端可能与结果格式不一致。所以,引入DTO是个好主意。

public class StudentPaginatedResponseDto {
 private int size;
 private long totalElements;
 private int totalPages;
 private List<Student> content;
 private int currentPage;

 public StudentPaginatedResponseDto(Page<Student> pageResult){
         this.setSize(pageResult.getSize());
         this.setTotalElements(pageResult.getTotalElements());
          this.setTotalPages(pageResult.getTotalPages());
         this.setCurrentPage(pageResult.getPageable().getPageNumber());
         this.setContent(pageResult.getContent());
 }

 public StudentPaginatedResponseDto get(){
          return this;
 }
}

服务方法:

@Override
public StudentPaginatedResponseDto getPaginatedList(int page, int size) {
   Pageable pageable = PageRequest.of(page, size);
   Page<Student> studentsPage = studentRepository.findAll(pageable);
   return new StudentPaginatedResponseDto(studentsPage).get();
}

它获取页面的页码和大小,并生成包含内容和详细信息的StudentPaginatedResponseDto 。


假设学生列表页面功能已经完成,我们要开始在教师列表页面上工作。

@NoArgsConstructor
@Data
public class TeacherPaginatedResponseDto {
   private int size;
   private long totalElements;
   private int totalPages;
   private List<Teacher> content;
   private int currentPage;

   public TeacherPaginatedResponseDto(Page<Teacher> pageResult){
       this.setSize(pageResult.getSize());
       this.setTotalElements(pageResult.getTotalElements());
       this.setTotalPages(pageResult.getTotalPages());
       this.setCurrentPage(pageResult.getPageable().getPageNumber());
       this.setContent(pageResult.getContent());
   }

   public TeacherPaginatedResponseDto get(){
       return this;
   }
}

现在暂停一下。想想我们的下一个要求。这可能是管理员列表页面、监护人列表页面等。我们应该为每种类型的列表编写一个...PaginatedResponseDto吗?

您肯定可以看出这两个类有如此多的相似之处。我们可以用通用的方式编写这个类,以便我们可以在我们的用例中重用它吗?

我们将使用泛型。我们将像这样创建一个新类:

@AllArgsConstructor
@NoArgsConstructor
@Data
public class GenericPaginatedResponseDto<T>{
   private int size;
   private long totalElements;
   private int totalPages;
   private List<T> content;
   private int currentPage;

   public GenericPaginatedResponseDto(Page<T> pageResult){
       this.setSize(pageResult.getSize());
       this.setTotalElements(pageResult.getTotalElements());
       this.setTotalPages(pageResult.getTotalPages());
       this.setCurrentPage(pageResult.getPageable().getPageNumber());
       this.setContent(pageResult.getContent());
   }

   public GenericPaginatedResponseDto<T> get(){
       return this;
   }
}

这里以通过类型参数化的方式创建了该类。所以获取学生列表的服务方法变为:

@Override
public GenericPaginatedResponseDto<Student> getPaginatedList(int page, int size) {
   Pageable pageable = PageRequest.of(page, size);
   Page<Student> studentsPage = studentRepository.findAll(pageable);
   return new GenericPaginatedResponseDto<Student>(studentsPage).get();
}

这是完整的项目:https ://github.com/Ruhshan/spring-boot-pagination-generics-example