How to Implement Filtering in Spring Boot: Simple Guide
In Spring Boot, you can implement filtering by accepting query parameters in your controller and using them to build database queries with
JpaSpecificationExecutor or ExampleMatcher. This allows dynamic filtering of data based on client requests.Syntax
Filtering in Spring Boot typically involves these parts:
- Controller method that accepts filter parameters via
@RequestParam. - Repository extending
JpaSpecificationExecutorfor dynamic queries. - Specification class that builds query conditions based on parameters.
java
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { } public class UserSpecification implements Specification<User> { private final String name; public UserSpecification(String name) { this.name = name; } @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { if (name == null || name.isEmpty()) { return cb.conjunction(); } return cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%"); } } @GetMapping("/users") public List<User> getUsers(@RequestParam(required = false) String name) { return userRepository.findAll(new UserSpecification(name)); }
Example
This example shows a Spring Boot REST controller filtering users by their name using JpaSpecificationExecutor. If no name is given, it returns all users.
java
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.persistence.*; import javax.persistence.criteria.*; import java.util.List; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // getters and setters } public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { } public class UserSpecification implements Specification<User> { private final String name; public UserSpecification(String name) { this.name = name; } @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { if (name == null || name.isEmpty()) { return cb.conjunction(); } return cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%"); } } @RestController public class UserController { private final UserRepository userRepository; public UserController(UserRepository userRepository) { this.userRepository = userRepository; } @GetMapping("/users") public List<User> getUsers(@RequestParam(required = false) String name) { return userRepository.findAll(new UserSpecification(name)); } }
Output
[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}] // when no filter
[{"id":1,"name":"Alice"}] // when ?name=ali
Common Pitfalls
- Not handling null or empty filter parameters causes errors or no results.
- Using string concatenation in queries can cause SQL injection risks; use
CriteriaBuildermethods instead. - Forgetting to extend
JpaSpecificationExecutorin the repository disables specification filtering. - Not making filter parameters optional in the controller leads to bad requests if parameters are missing.
java
/* Wrong: Not handling null filter */ @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { return cb.like(root.get("name"), "%" + name + "%"); // throws NullPointerException if name is null } /* Right: Handle null safely */ @Override public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { if (name == null || name.isEmpty()) { return cb.conjunction(); } return cb.like(cb.lower(root.get("name")), "%" + name.toLowerCase() + "%"); }
Quick Reference
Tips for filtering in Spring Boot:
- Use
@RequestParam(required = false)for optional filters. - Extend
JpaSpecificationExecutorin your repository for flexible queries. - Create
Specificationclasses to build dynamic predicates. - Always handle null or empty filter values to avoid errors.
- Use
CriteriaBuildermethods to prevent SQL injection.
Key Takeaways
Use JpaSpecificationExecutor and Specification to implement dynamic filtering in Spring Boot.
Make filter parameters optional and handle null or empty values safely.
Avoid string concatenation in queries; use CriteriaBuilder methods for security.
Extend your repository interface with JpaSpecificationExecutor to enable filtering.
Test filtering endpoints with and without parameters to ensure correct behavior.