In general, Spring Data JPA module implements the Spring Data Commons repository abstraction to ease repository implementations. As well as the Spring Data repository approach allows you to get rid of most of the implementation code by using a plain interface definition. You’ve leveraged repository implementation in your applications by creating an interfaces that extends the Repository that provided by the Spring Data infrastructure.
The Spring Data Repository captures the type of domain class as well as the type identity. But that isn’t the whole story, Spring Data, also provides different kinds of repositories.
So Spring Data provides you the following repositories.
- Repository: A plain marker interface to let the Spring Data infrastructure pick up user defined repositories (configuration wise).
- CrudRepository: Extends Repository and adds basic persistence methods like saving, finding and deleting entities.
- PagingAndSortingRepositories: Extends CrudRepository and adds methods for accessing entities page by page ans sorting them by given criteria.
This tutorial guides you through a sample application to implement PrimeFaces, Spring Data and MySQL database using the PagingAndSortingRepositories to paginate the display of data. If you have any questions, please write it in the comments section.
Also read:
Lets look at how EmployeeRepository inherits the CrudRespository provided by Spring Data.
EmployeeRepository.java
package net.javabeat.springdata.repo; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends CrudRepository<Employee,Integer>{ }
The EmployeeRepository interface now will inherit all of these methods defined in the CurdRepository which lead us for repository containing those defined methods in the CurdRepository itself.
CrudRepository.java (This is Spring Data API implementation)
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { <S extends T> save(S entity); <S extends T> Iterable<S> save(Iterable<S> entities); T findOne(ID id); Iterable<T> findAll(); void delete(ID id); void delete(T entity); void deleteAll(); }
So, it contains methods to save a single entity as well as an Iterable of entities, finder methods for single entity or all entities, and delete methods of different flavors. PagingAndSortingRepository now in turn extends CrudRepository and adds methods to allow handing instances of Pagable and Sort into the generic findAll methods to actually access entities page by page.
This tutorial would give the PagingAndSortingRepository example application with user interface developed using PrimeFaces.
1. Database Tables
It’s just a depicts for the database models that used for implementing the enterprise sample that really depends on a real record.
Queries For Tables Creation
CREATE TABLE `address` ( `addressId` bigint(20) NOT NULL AUTO_INCREMENT, `addressCountry` varchar(45) DEFAULT NULL, `addressCity` varchar(45) DEFAULT NULL, PRIMARY KEY (`addressId`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; SELECT * FROM javabeat.employee; CREATE TABLE `employee` ( `employeeId` bigint(20) NOT NULL AUTO_INCREMENT, `employeeName` varchar(20) DEFAULT NULL, `address` bigint(20) DEFAULT NULL, PRIMARY KEY (`employeeId`), KEY `FK_EMP_ADD` (`address`), CONSTRAINT `FK_EMP_ADD` FOREIGN KEY (`address`) REFERENCES `address` (`addressId`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
2. Business Domain
As you knew before, the JPA contains two major parts, the mapping and the entity manager. Here, we’ll list the mapping classes, which will be used later for achieving the CRUD operations against defined database models mentioned in the previous section.
Address.java
package net.javabeat.springdata.jpa.data; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; @Entity(name = "address") public class Address { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer addressId; private String addressCountry = ""; private String addressCity = ""; @OneToOne(cascade = CascadeType.ALL, mappedBy = "address") private Employee employee; public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } public Integer getAddressId() { return addressId; } public void setAddressId(Integer addressId) { this.addressId = addressId; } public String getAddressCountry() { return addressCountry; } public void setAddressCountry(String addressCountry) { this.addressCountry = addressCountry; } public String getAddressCity() { return addressCity; } public void setAddressCity(String addressCity) { this.addressCity = addressCity; } }
Employee.java
package net.javabeat.springdata.jpa.data; import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; @Entity public class Employee { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer employeeId; @Basic(optional = false) private String employeeName; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "Address") private Address address = new Address(); public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Integer getEmployeeId() { return employeeId; } public void setEmployeeId(Integer employeeId) { this.employeeId = employeeId; } public String getEmployeeName() { return employeeName; } public void setEmployeeName(String employeeName) { this.employeeName = employeeName; } }
3. Spring Data Repositories
PagingAndSortingRepository would be used for implementing the Spring Data operations. It is the specialized version of the CrudRepository interface. PagingAndSortingRepository defines extra methods for finding the rows by passing the page numbers. Lets look at the example implementation for AddressRepository and EmployeeRepository classes.
AddressRepositiry.java
package net.javabeat.springdata.repo; import net.javabeat.springdata.jpa.data.Address; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface AddressRepository extends PagingAndSortingRepository<Address,Integer>{ }
EmployeeRepository.java
package net.javabeat.springdata.repo; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface EmployeeRepository extends PagingAndSortingRepository<Employee,Integer>{ }
4. Spring Context Configuration
Here is the XML Spring configuration that used for configuring Spring beans, repositories and MySQL entity manager.
SpringContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- For consider the using of annotations foe defining Spring Bean --> <context:annotation-config /> <!-- For defining Spring Bean --> <context:component-scan base-package="net.javabeat.springdata.beans" /> <!-- For bootstrapping the Spring Repository --> <jpa:repositories base-package="net.javabeat.springdata.repo" /> <!-- Necessary to get the entity manager injected into the factory bean --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <!-- Define EclipseLink JPA Vendor Adapter --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <!-- Entity Manager Factory --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="SpringData"></property> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> </bean> <!-- Transaction Manager --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- Enable Transactional Manner --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
5. Spring Bean Service
Here is the Spring component had used for retaining a repositories proxies.
RegistrationService.java
package net.javabeat.springdata.beans; import net.javabeat.springdata.repo.EmployeeRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class RegistrationService { @Autowired private EmployeeRepository employeeRepository; public EmployeeRepository getEmployeeRepository() { return employeeRepository; } public void setEmployeeRepository(EmployeeRepository employeeRepository) { this.employeeRepository = employeeRepository; } }
6. Primefaces Managed Beans
It’s the managed bean that used for holding the business logic for the primefaces view.
RegistrationManagedBean.java
package net.javabeat.primefaces.managedbeans; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.SessionScoped; import net.javabeat.springdata.beans.RegistrationService; import net.javabeat.springdata.jpa.data.Employee; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; @ManagedBean @SessionScoped public class RegistrationManagedBean { private Employee employee = new Employee(); private List<Employee> employees = new ArrayList<Employee>(); private Page<Employee> page; public RegistrationManagedBean(){ } @PostConstruct public void postInitialization(){ // Create & Initialize a Sort Object Sort sort = new Sort(Direction.ASC,"employeeName"); // Create & Initialize a Page Object page = this.service.getEmployeeRepository().findAll(new PageRequest(0, 3,sort)); // Fetch the employees from the page object this.employees = page.getContent(); } @ManagedProperty(value="#{registrationService}") private RegistrationService service; public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } public String nextEmployees(){ if(page.hasNextPage()){ this.page = this.service.getEmployeeRepository().findAll(page.nextPageable()); this.employees = page.getContent(); } return ""; } public String previousEmployees(){ if(page.hasPreviousPage()){ this.page = this.service.getEmployeeRepository().findAll(page.previousPageable()); this.employees = page.getContent(); } return ""; } public String sortByEmployeeName(){ if(page != null){ if(page.getSort() != null){ Sort sort= new Sort(Direction.ASC,"employeeName"); this.page = this.service.getEmployeeRepository().findAll(new PageRequest(this.page.getNumber(), this.page.getSize(), sort)); this.employees = this.page.getContent(); } } return ""; } public String sortByEmployeeId(){ if(page != null){ if(page.getSort() != null){ Sort sort= new Sort(Direction.ASC,"employeeId"); this.page = this.service.getEmployeeRepository().findAll(new PageRequest(this.page.getNumber(), this.page.getSize(), sort)); this.employees = this.page.getContent(); } } return ""; } public RegistrationService getService() { return service; } public void setService(RegistrationService service) { this.service = service; } public Page<Employee> getPage() { return page; } public void setPage(Page<Employee> page) { this.page = page; } public String register(){ this.service.getEmployeeRepository().save(this.employee); this.employee = new Employee(); return ""; } }
7. Faces Configuration File
For making the Spring beans referenced by the faces managed beans, your face-config.xml should look like
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2"> <application> <resource-bundle> <base-name>net.javabeat.jsf.application</base-name> <var>msg</var> </resource-bundle> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> </faces-config>
8. Primefaces View
It’s the primefaces view page.
index.xhtml
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <h:head> <script name="jquery/jquery.js" library="primefaces"></script> </h:head> <f:view> <h:form prependId="false"> <h2>JavaBeat Tutorials</h2> <h2>Primefaces + Spring Data + PagingAndSortingRepository + MySQL</h2> <div style="width: 700px;border: 1px;border-style: dotted;"> <h:panelGrid columns="2"> <h:outputText value="Enter Employee Name:"/> <p:inputText value="#{registrationManagedBean.employee.employeeName}"></p:inputText> <h:outputText value="Enter Employee Address Country:"/> <p:inputText value="#{registrationManagedBean.employee.address.addressCountry}"></p:inputText> <h:outputText value="Enter Employee Address City:"/> <p:inputText value="#{registrationManagedBean.employee.address.addressCity}"></p:inputText> </h:panelGrid> <p:commandButton value="Register" action="#{registrationManagedBean.register}" ajax="false"/> <p:separator/> <h:panelGrid columns="1" width="100%"> <p:dataTable value="#{registrationManagedBean.employees}" var="employee" style="width:100%"> <p:column headerText="Employee's Name"> <h:outputText value="#{employee.employeeName}"/> </p:column> <p:column headerText="Employee's Country"> <h:outputText value="#{employee.address.addressCountry}"/> </p:column> <p:column headerText="Employee's City"> <h:outputText value="#{employee.address.addressCity}"/> </p:column> </p:dataTable> <h:panelGrid columns="4" width="100%"> <p:commandButton value="Next Employees" action="#{registrationManagedBean.nextEmployees}" ajax="false"/> <p:commandButton value="Previous Employees" action="#{registrationManagedBean.previousEmployees}" ajax="false"/> <p:commandButton value="Sort By Employee Name" action="#{registrationManagedBean.sortByEmployeeName}" ajax="false"/> <p:commandButton value="Sort By Employee Id" action="#{registrationManagedBean.sortByEmployeeId}" ajax="false"/> </h:panelGrid> </h:panelGrid> </div> </h:form> </f:view> </html>
9. Web Deployment Descriptor
It’s the deployment descriptor for this sample application.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" metadata-complete="true" version="2.5"> <context-param> <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2 </description> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param> <context-param> <param-name>javax.faces.application.CONFIG_FILES</param-name> <param-value>/WEB-INF/faces-config.xml</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-config/*.xml</param-value> </context-param> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> </web-app>
10. Maven Build File
This is maven build file used for building this application.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>next.javabeat.jsf</groupId> <artifactId>JavaBeat-Primefaces-SpringData-PagingAndSortingRepository-MySQL</artifactId> <packaging>war</packaging> <version>1.0</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.7</java.version> <junit.version>4.9</junit.version> <slf4j.version>1.6.4</slf4j.version> <logback.version>1.0.1</logback.version> <log4j.version>1.2.14</log4j.version> <servlet.version>2.5</servlet.version> <jsp.version>2.1</jsp.version> <jstl.version>1.2</jstl.version> <taglibs-standard.version>1.1.2</taglibs-standard.version> <maven.compiler.plugin>2.3.2</maven.compiler.plugin> <maven.failsafe.plugin>2.4.3-alpha-1</maven.failsafe.plugin> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <repositories> <repository> <id>prime-repo</id> <name>PrimeFaces Maven Repository</name> <url>http://repository.primefaces.org</url> <layout>default</layout> </repository> </repositories> <dependencies> <!-- Servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <!-- Faces Implementation --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.2.4</version> </dependency> <!-- Faces Library --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.2.4</version> </dependency> <!-- Primefaces Version 5 --> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>5.0.RC2</version> </dependency> <!-- JSP Library --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <!-- JSTL Library --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.1.2</version> </dependency> <!-- Spring Core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.0.3.RELEASE</version> </dependency> <!-- Spring Web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.3.RELEASE</version> </dependency> <!-- Google List Library --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>r09</version> </dependency> <!-- Dependencies for Eclipse JPA Persistence API --> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.5.0-RC1</version> <exclusions> <exclusion> <groupId>org.eclipse.persistence</groupId> <artifactId>commonj.sdo</artifactId> </exclusion> </exclusions> </dependency> <!-- Spring Data Dependency --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.5.2.RELEASE</version> </dependency> <!-- Dependency for MySql Java connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.30</version> </dependency> </dependencies> </project>
11. PagingAndSortingRepository Demo
The scenario implemented here contains of set of employees that could be paginated. For every single page the total amount of employees that shown inside is three. The user has the ability to add employees, see the next page, see the previous page and sorting by employee name and employee Id.
12. Summary
You’ve just developed a Spring Data application using PagingAndSortingRepository. That repository provides you a pagination feature for your data. If you have any questions. please write it in the comments section.