Spring MVC 4 REST + JPA 2 + Hibernate without persistence.xml
February 21, 2017
This page will walk through spring MVC 4 REST + JPA 2 + hibernate without persistence.xml. We will create a REST application that will return JSON response to the user. The data will be fetched using JPA from MySQL database. To avoid persistence.xml
, in spring 3.1 to scan JPA entities, spring has added packagesToScan
feature that can be used while configuring entity manager factory. So we need not to use persistence.xml
file to integrate JPA. Here we will provide JavaConfig as well as XML configuration to integrate JPA with spring to query database. In our REST application we will return JSON response. To indent the JSON response we will use Jackson 2 message converter. To query the data from database we will use JPA EntityManager
that will be instantiated using dependency injection with @PersistenceContext
annotation in our DAO class. To support database transaction management using @Transactional
annotation, spring provides JpaTransactionManager
class. For database configuration, we will use BasicDataSource
class from commons.dbcp2 library. To create a REST web service, our controller class will be annotated with @RestController
. Now let us create our complete example using JavaConfig and XML configuration step by step.
Contents
- Software Used
- Gradle and Maven to Build the Project
- MySQL Database and JPA Entity
- Spring MVC 4 REST + JPA 2 + Hibernate using Annotation
- 1. Project Structure using JavaConfig in Eclipse
- 2. Database and JPA Configuration without persistence.xml using JavaConfig
- 3. Spring MVC Configuration
- 4. Create DAO and Service
- 5. Spring REST Controller
- Spring MVC 4 REST + JPA 2 + Hibernate using XML Configuration
- 1. Project Structure using XML Configuration in Eclipse
- 2. Database and JPA Configuration without persistence.xml using XML Configuration
- 3. Spring MVC XML Configuration
- 4. web.xml
- Run Application
- Reference
- Download Source Code
Software Used
We are using following software in our example.1. Java 8
2. Spring 4.3
3. Gradle 3.3
4. Maven 3.3
5. Tomcat 8.0
6. MySQL 5.5
7. Eclipse Mars
Gradle and Maven to Build the Project
Find the gradle file to build the project.build.gradle
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'war' war.archiveName 'spring-app.war' repositories { mavenCentral() } dependencies { compile 'org.springframework.boot:spring-boot-starter-web:1.5.1.RELEASE' compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.5.1.RELEASE' compile 'mysql:mysql-connector-java:6.0.5' compile 'org.apache.commons:commons-dbcp2:2.1.1' compile 'jstl:jstl:1.2' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.1.RELEASE' }
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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.concretepage</groupId> <artifactId>spring-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>Spring</name> <description>Spring Demo Project</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> <relativePath/> </parent> <properties> <java.version>1.8</java.version> <context.path>spring-app</context.path> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.5</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.0.0</version> <configuration> <warName>${context.path}</warName> </configuration> </plugin> </plugins> </build> </project>
MySQL Database and JPA Entity
In our demo we have create a table which will keep person information. Find the table with seed data.Database Schema
-- Dumping database structure for concretepage CREATE DATABASE IF NOT EXISTS `concretepage`; USE `concretepage`; -- Dumping structure for table concretepage.person CREATE TABLE IF NOT EXISTS `person` ( `pid` int(5) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `city` varchar(100) NOT NULL, PRIMARY KEY (`pid`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1; -- Dumping data for table concretepage.person: ~3 rows (approximately) INSERT INTO `person` (`pid`, `name`, `city`) VALUES (1, 'Mahesh', 'Varanasi'), (2, 'Ram', 'Ayodhya'), (3, 'Krishna', 'Mathura');
Person.java
package com.concretepage.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="person") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name="pid") private int pid; @Column(name="name") private String name; @Column(name="city") private String city; public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
Spring MVC 4 REST + JPA 2 + Hibernate using Annotation
In this application, we will create spring MVC 4 REST + JPA 2 + hibernate using annotation. We will create two JavaConfig files, one for spring MVC configuration and another for JPA configuration. We will configure JPA withoutpersistence.xml
file. For the demo we will fetch data from database and a JSON response will be returned to the user. Let us understand our application step by step.
1. Project Structure using JavaConfig in Eclipse
Find the project structure using JavaConfig in eclipse.2. Database and JPA Configuration without persistence.xml using JavaConfig
Find the JPA and spring integration configuration to interact with database using JavaConfig.DBConfig.java
package com.concretepage.config; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @PropertySource("classpath:database.properties") public class DBConfig { @Autowired private Environment env; @Bean public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() { LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean(); lcemfb.setJpaVendorAdapter(getJpaVendorAdapter()); lcemfb.setDataSource(getDataSource()); lcemfb.setPersistenceUnitName("myJpaPersistenceUnit"); lcemfb.setPackagesToScan("com.concretepage.entity"); lcemfb.setJpaProperties(jpaProperties()); return lcemfb; } @Bean public JpaVendorAdapter getJpaVendorAdapter() { JpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); return adapter; } @Bean public DataSource getDataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(env.getProperty("database.driverClassName")); dataSource.setUrl(env.getProperty("database.url")); dataSource.setUsername(env.getProperty("database.username")); dataSource.setPassword(env.getProperty("database.password")); return dataSource; } @Bean public PlatformTransactionManager txManager(){ JpaTransactionManager jpaTransactionManager = new JpaTransactionManager( getEntityManagerFactoryBean().getObject()); return jpaTransactionManager; } private Properties jpaProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql")); properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql")); return properties; } }
1. Create data source using
BasicDataSource
class from the commons.dbcp2
library. Using this class we configure database driver class name, URL, username and password.
2. Create entity manager factory bean using the following class.
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
EntityManagerFactory
according to the standard container bootstrap contract of JPA. In this way we get a shared EntityManagerFactory
in our spring application context. To use it in DAO we just do dependency injection to get its instance. To create entity manager factory bean we specify the values to following setter methods.
setJpaVendorAdapter()
: Specify an implementation of JpaVendorAdapter
that will act as JPA provider. In our example we are specifying HibernateJpaVendorAdapter
which is the implementation of JpaVendorAdapter
that will facilitate to get hibernate EntityManager
.
setDataSource()
: Specify data source that will be used by JPA persistence API.
setPersistenceUnitName()
: This is the default persistence unit name.
setPackagesToScan()
: Specify the package name that contains JPA entities. In spring 3.1 setPackagesToScan()
method has been added to scan JPA entities and hence using JavaConfig we can integrate JPA without persistence.xml
file.
setJpaProperties()
: Specify JPA properties that will be passed to method that creates entity manager factory as following.
Persistence.createEntityManagerFactory()
3. For database transaction management, spring provides
JpaTransactionManager
that is the implementation of PlatformTransactionManager
. JpaTransactionManager
is appropriate for single JPA EntityManagerFactory
for transactional data access.
4.
@EnableTransactionManagement
enables annotation-driven transaction management capability. To handle transaction at DAO layer, we annotate DAO class or method with @Transactional
annotation.
Find the database property file.
database.properties
database.driverClassName=com.mysql.cj.jdbc.Driver database.url=jdbc:mysql://localhost:3306/concretepage database.username=root database.password= hibernate.dialect = org.hibernate.dialect.MySQLDialect hibernate.show_sql = true hibernate.format_sql = true
@PropertySource("classpath:database.properties")
Environment
we fetch the proprieties.
3. Spring MVC Configuration
Find the MVC configuration using JavaConfig. Here we will configure message converter to indent our JSON response.AppConfig.java
package com.concretepage.config; import java.util.List; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @ComponentScan("com.concretepage") @EnableWebMvc public class AppConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true); converters.add(new MappingJackson2HttpMessageConverter(builder.build())); } }
@Configuration
: The java class that declares bean annotated with @Bean
. We use @Configuration
annotation at class level.
@ComponentScan
: Defines base package for the classes which will use stereotype annotation for auto scanning.
@EnableWebMvc
: Inherits the default spring MVC configuration from WebMvcConfigurationSupport
class.
WebMvcConfigurerAdapter
: This is the empty implementation for the methods of WebMvcConfigurer
interface. WebMvcConfigurerAdapter
class will be used to override any specific method that is required to define.
HttpMessageConverter
: This is the interface for converters. Converter converts data from and to HTTP request and response.
Jackson2ObjectMapperBuilder
: This is a builder to create Jackson ObjectMapper
. Here we configure formats for JSON elements such as date etc. We can also configure to indent JSON output.
MappingJackson2HttpMessageConverter
: This is the implementation of HttpMessageConverter
to read and write JSON using Jackson 2.x.
configureMessageConverters()
: This is used to configure HttpMessageConverter
such as MappingJackson2HttpMessageConverter
.
Now find the web application initializer to register
DispatcherServlet
and configure spring MVC configuration class annotated with @Configuration
.
WebAppInitializer.java
package com.concretepage.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[]{ "/" }; } }
4. Create DAO and Service
Find the DAO class. Here we have created a method that is usingEntityManager
to fetch the data from database.
PersonDAO.java
package com.concretepage.dao; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import com.concretepage.entity.Person; @Repository @Transactional public class PersonDAO { @PersistenceContext private EntityManager entityManager; @SuppressWarnings("unchecked") public List<Person> getAllPersons() { List<?> list = entityManager.createQuery("SELECT p FROM Person p").getResultList(); return (List<Person>) list; } }
@Repository
: This is a spring stereotype annotation. We annotate that class with it which serves the data storage and retrieval related task. Spring container will auto scan such classes if they reside within component base package defined in configuration class.
@Transactional
: This defines the transaction attributes on the class level or method level. Transaction attributes are isolation, propagation, timeout etc. If we do not specify transaction attributes then their default values will be considered.
@PersistenceContext
: JPA API for dependency injection. In our example we have instantiated JPA EntityManager
to query database.
EntityManager
: This API is used to interact with persistence context. EntityManager
manages JPA entities defined in our application. It can create and remove entity instances. In our example we are calling its method createQuery()
which will accept persistence query language and return the instance of JPA Query
and then using its getResultList()
method we get the result as list of rows.
Now create a service class.
PersonService.java
package com.concretepage.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.concretepage.dao.PersonDAO; import com.concretepage.entity.Person; @Service public class PersonService { @Autowired private PersonDAO personDAO; public List<Person> getAllData() { return personDAO.getAllPersons(); } }
5. Spring REST Controller
We are creating a REST controller that will return JSON response. In our demo we have created a method that will return a list of all persons in our database.PersonController.java
package com.concretepage.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.concretepage.entity.Person; import com.concretepage.service.PersonService; @RestController @RequestMapping("person") public class PersonController { @Autowired private PersonService service; @GetMapping(value="details") public List<Person> getPersonDetails() { List<Person> persons = service.getAllData(); return persons; } }
@RestController
: This is the combination of @Controller
and @ResponseBody
annotations. To achieve the combined goal we can use @RestController
annotation in our controller class.
@RequestMapping
: This plays the role of mapping HTTP requests to a class and methods in controller class.
@GetMapping
: This is equal to define @RequestMapping
with HTTP GET method as follows.
@RequestMapping(method = RequestMethod.GET)
@GetMapping for HTTP GET method
@PostMapping for HTTP POST method
@PutMapping for HTTP PUT method
@DeleteMapping for HTTP DELETE method
Spring MVC 4 REST + JPA 2 + Hibernate using XML Configuration
In this application we will create spring MVC 4 REST + JPA 2 + hibernate using XML configuration withoutpersistence.xml
file. We will create two XML files, one for spring MVC configuration and another for JPA configuration. The DAO, service and controller class will be the same as in the application using JavaConfig. The application will fetch data from database and return response in JSON format. Let us understand complete application step by step.
1. Project Structure using XML Configuration in Eclipse
Find the project structure using XML configuration in eclipse.2. Database and JPA Configuration without persistence.xml using XML Configuration
Find the XML namespace for JPA configuration to interact with database.db-config.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:database.properties"/> <bean id="basicDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> </bean> <bean name="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> <bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" /> <property name="dataSource" ref="basicDataSource" /> <property name="persistenceUnitName" value="myJpaPersistenceUnit" /> <property name="packagesToScan"> <list> <value>com.concretepage.entity</value> </list> </property> <property name="jpaProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> </props> </property> </bean> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactoryBean" /> </bean> <bean class="com.concretepage.dao.PersonDAO"/> <tx:annotation-driven transaction-manager="txManager" /> </beans>
1. First of all we have created a bean for data source using following class.
org.apache.commons.dbcp2.BasicDataSource
BasicDataSource
is used to configure database driver name, URL, username and password.
2. Now we are creating a JPA vendor adapter bean using
HibernateJpaVendorAdapter
class. So JPA will use hibernate persistence provider.
3. To get the entity manager factory we need to create a bean for following class.
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
EntityManagerFactory
and then we get EntityManager
from this factory in our DAO using dependency injection to interact with database. Like JavaConfig for JPA, here we will configure properties such as jpaVendorAdapter, dataSource, persistenceUnitName, packagesToScan and jpaProperties. In spring 3.1 packagesToScan
feature has been added so that we can integrate JPA without persistence.xml
file.
4. For transaction management we have configured
JpaTransactionManager
and we have enabled annotation-driven transaction management.
3. Spring MVC XML Configuration
In our example the REST service will respond JSON. To indent JSON we are using message converter as follows.dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.concretepage" /> <bean name="jackson2ObjectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="indentOutput" value="true"/> </bean> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper" ref="jackson2ObjectMapper" /> </bean> </mvc:message-converters> </mvc:annotation-driven> </beans>
<context:component-scan>
: It specifies base package to scan classes annotated with @RestController
, @Service
etc.
<mvc:annotation-driven>
: It allows annotation-driven spring MVC controller programming model.
<mvc:message-converters>
: It configures one or more HttpMessageConverter
.
Jackson2ObjectMapperFactoryBean
: It is a FactoryBean
that creates Jackson 2.x ObjectMapper
or XmlMapper
. Here we can enable and disable Jackson features. In our example we have enabled to indent JSON response.
MappingJackson2HttpMessageConverter
: This is a HttpMessageConverter
implementation class based on Jackson 2.x. This converter reads and write JSON.
4. web.xml
Find theweb.xml
used in our example.
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/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Spring Demo Project</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/dispatcher-servlet.xml /WEB-INF/db-config.xml </param-value> </context-param> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
DispatcherServlet
: It maps HTTP requests to a spring MVC controller and its methods.
ContextLoaderListener
: It listens startup and shutdown of web application context in spring root.
Run Application
To build and run the demo application, follow the steps.1. Import database in MySQL given above on this page.
2. Download the source code from the link given below on this page.
3. Go to the root directory of the project using command prompt.
4. Build the project using gradle with following command.
gradle clean build
mvn clean package
5. Deploy the WAR file using tomcat and access the URL as given below.
http://localhost:8080/spring-app/person/details
I am done now. Happy Spring Learning!