今天,我将分享一个真实的场景,在这个场景中,我能够将 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