The combination of Specification and Pageable in Spring Data JPA makes it super easy to fetch data with dynamic conditions and pagination. Let's walk through a step-by-step example using a Student entity.
1. Setting up the Project
Make sure you have the necessary dependencies in your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2. Define the Entity
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String course;
private Double grade;
// getters, setters, etc.
}
3. Create the Repository:
Extend both JpaRepository and JpaSpecificationExecutor:
public interface StudentRepository extends JpaRepository<Student, Long>, JpaSpecificationExecutor<Student> {
}
4. Define Specifications
public class StudentSpecifications {
public static Specification<Student> hasName(String name) {
return (root, query, criteriaBuilder) -> criteriaBuilder.like(root.get("name"), "%" + name + "%");
}
public static Specification<Student> inCourse(String course) {
return (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("course"), course);
}
public static Specification<Student> hasGradeAbove(Double grade) {
return (root, query, criteriaBuilder) -> criteriaBuilder.greaterThan(root.get("grade"), grade);
}
}
5. Create a Service to Query with Pagination
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepository;
public Page<Student> findStudents(String name, String course, Double grade, Pageable pageable) {
return studentRepository.findAll(
Specification.where(StudentSpecifications.hasName(name))
.and(StudentSpecifications.inCourse(course))
.and(StudentSpecifications.hasGradeAbove(grade)),
pageable
);
}
}
6. Using the Service:
You can use the PageRequest class to create an instance of Pageable:
@Autowired
private StudentService studentService;
public void fetchStudents() {
Pageable firstPageWithTwoElements = PageRequest.of(0, 2);
Page<Student> students = studentService.findStudents("John", "Mathematics", 80.0, firstPageWithTwoElements);
// Access the list of students using students.getContent()
for (Student student : students.getContent()) {
// process each student
}
}
7. Extending to Controllers
If you are integrating this into a web application, it's typical to pass pagination parameters like page, size, and sort from the client side:
@RestController
@RequestMapping("/students")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping
public ResponseEntity<Page<Student>> getStudents(
@RequestParam(required = false) String name,
@RequestParam(required = false) String course,
@RequestParam(required = false) Double grade,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "id,asc") String[] sort) {
List<Sort.Order> orders = new ArrayList<>();
for (String sortOrder : sort) {
String[] _sort = sortOrder.split(",");
orders.add(new Sort.Order(_sort[1].equalsIgnoreCase("desc") ? Sort.Direction.DESC : Sort.Direction.ASC, _sort[0]));
}
Page<Student> students = studentService.findStudents(name, course, grade, PageRequest.of(page, size, Sort.by(orders)));
return new ResponseEntity<>(students, HttpStatus.OK);
}
}
That's it! With this setup, you can create dynamic queries based on filters (like name, course, and grade) and fetch results with pagination and sorting.
Comments
Post a Comment
Leave Comment