1

I am trying to implement pagination as well filter in server side.

These two ways i went through to implement. i am using spring data jpa.

1.Use the JpaSpecificationExecutor and write a Specification

2.Use the QueryDslPredicateExecutor and use QueryDSL to write a predicate.

i started with JpaSpecificationExecutor but found it complex.

Here is my Specification Class:

public class TransmissionSearchSpecification implements Specification {

 private TransmissionSearch criteria;
 
 public TransmissionSearchSpecification(TransmissionSearch ts) {
        criteria= ts;
    }

@Override
public Predicate toPredicate(Root<TransmissionView> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {
    Path<String> thirdParty = root.get(TransmissionView_.thirdPartyName);
    
     final List<Predicate> predicates = new ArrayList<Predicate>();
        if(criteria.getThirdPartyName() !=null) {
            predicates.add(builder.equal(thirdParty, criteria.getThirdPartyName()));
        }
       
        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
    
}

public class TransmissionController {

private final TransmissionViewService transmissionViewService; 

public  TransmissionController(TransmissionViewService transmissionViewService) {
    this.transmissionViewService = transmissionViewService;

}

@RequestMapping("/transmissions/search")
@GetMapping
public ResponseEntity<Page<TransmissionView>> getTransmissions(TransmissionSearch transmissionSearch, Pageable pageable){
    Page<TransmissionView> transmissions = transmissionViewService.findTransmissions(pageable);
    if(!CollectionUtils.isEmpty(transmissions.getContent())) {
        return new ResponseEntity<>(transmissions, HttpStatus.OK);
    } else {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}

Is there any other way that can ease the filter and pagination .Please suggest. Thanks in advance

Community
  • 1
  • 1
Amit Swain
  • 301
  • 1
  • 6
  • 11

1 Answers1

1

What is the best Way to achieve Pagination with filtering in spring data jpa?

I think to use Spring Data with QueryDsl and Web support extensions.

First you need to plug QueryDsl to you project:

<dependencies>
    //...
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <version>${querydsl.version}</version>
    </dependency>

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
    </dependency>

</dependencies>
<build>
    <plugins>
        //...
        <plugin>
            <groupId>com.mysema.maven</groupId>
            <artifactId>apt-maven-plugin</artifactId>
            <version>1.1.3</version>
            <executions>
                <execution>
                    <goals>
                        <goal>process</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>target/generated-sources/annotations</outputDirectory>
                        <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

(Don't forget then to perform maven 'compile' goal...)

Then create a repo with QueryDslPredicateExecutor, QuerydslBinderCustomizer and optional 'customize' method (see details bellow in 'more info'):

public interface TransmissionRepo extends JpaRepository<Transmission, Long>, QueryDslPredicateExecutor<Transmission>, QuerydslBinderCustomizer<Transmission> {

  @Override
  default void customize(QuerydslBindings bindings, QTransmission transmission) {

    bindings.excluding( 
        // excluding some fields from filter 
        transmission.id,
        transmission.version
    );

    // implement ignore case to strings...
    bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase);

    // https://stackoverflow.com/a/35158320/5380322
    // 'between' implementation - if you need this...
    bindings.bind(listing.createdOn).all((path, value) -> {

      Iterator<? extends LocalDate> it = value.iterator();
      LocalDate from = it.next();
      if (value.size() >= 2) {
        LocalDate to = it.next();
        return path.between(from, to);
      } else {
        return path.eq(from);
      }
    });
  }
}

Then if you use Spring Data REST in your project you can use your filter as well as pagination:

GET /transmissions?page=1&size=10&sort=field1,desc&field2=value2&field3=value3

Or you can implement your custom controller, for example like this:

@GetMapping("/transmissions")
@ResponseBody
public Iterable<Transmission> findAll(@QuerydslPredicate(root = Transmission.class) Predicate predicate, Pageable pageable) {
    return TransmissionRepo.findAll(predicate, pageable);
}

More info according your question you can find here.

Cepr0
  • 28,144
  • 8
  • 75
  • 101