CREATE TABLE CONTACTS
(
id INT PRIMARY KEY AUTO_INCREMENT,
firstname VARCHAR(30),
lastname VARCHAR(30),
telephone VARCHAR(15),
email VARCHAR(30),
created TIMESTAMP DEFAULT NOW()
);
Code language: SQL (Structured Query Language) (sql)
package net.viralpatel.contact.form;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="CONTACTS")
public class Contact {
@Id
@Column(name="ID")
@GeneratedValue
private Integer id;
@Column(name="FIRSTNAME")
private String firstname;
@Column(name="LASTNAME")
private String lastname;
@Column(name="EMAIL")
private String email;
@Column(name="TELEPHONE")
private String telephone;
public String getEmail() {
return email;
}
public String getTelephone() {
return telephone;
}
public void setEmail(String email) {
this.email = email;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
Code language: Java (java)
The first thing you’ll notice is that the import statements import from javax.persistence rather than a Hibernate or Spring package. Using Hibernate with Spring, the standard JPA annotations work just as well and that’s what I’m using here. @Entity
which tells Hibernate that this class represents an object that we can persist.@Table(name = "CONTACTS")
annotation tells Hibernate which table to map properties in this class to. The first property in this class on line 16 is our object ID which will be unique for all events persisted. This is why we’ve annotated it with @Id
.@GeneratedValue
annotation says that this value will be determined by the datasource, not by the code.@Column(name = "FIRSTNAME")
annotation is used to map this property to the FIRSTNAME column in the CONTACTS table.ContactDAO
and its corresponding implementation class ContactDAOImpl
. Create following Java files in net.viralpatel.contact.dao
package. File: src/main/java/net/viralpatel/contact/dao/ContactDAO.java package net.viralpatel.contact.dao;
import java.util.List;
import net.viralpatel.contact.form.Contact;
public interface ContactDAO {
public void addContact(Contact contact);
public List<Contact> listContact();
public void removeContact(Integer id);
}
Code language: Java (java)
File: src/main/java/net/viralpatel/contact/dao/ContactDAOImpl.java package net.viralpatel.contact.dao;
import java.util.List;
import net.viralpatel.contact.form.Contact;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class ContactDAOImpl implements ContactDAO {
@Autowired
private SessionFactory sessionFactory;
public void addContact(Contact contact) {
sessionFactory.getCurrentSession().save(contact);
}
public List<Contact> listContact() {
return sessionFactory.getCurrentSession().createQuery("from Contact")
.list();
}
public void removeContact(Integer id) {
Contact contact = (Contact) sessionFactory.getCurrentSession().load(
Contact.class, id);
if (null != contact) {
sessionFactory.getCurrentSession().delete(contact);
}
}
}
Code language: Java (java)
The DAO class in above code ContactDAOImpl
implements the data access interface ContactDAO
which defines methods such as listContact()
, addContact()
etc to access data from database. Note that we have used two Spring annotations @Repository
and @Autowired
. Classes marked with annotations are candidates for auto-detection by Spring when using annotation-based configuration and classpath scanning. The @Component
annotation is the main stereotype that indicates that an annotated class is a “component”. The @Repository
annotation is yet another stereotype that was introduced in Spring 2.0. This annotation is used to indicate that a class functions as a repository and needs to have exception translation applied transparently on it. The benefit of exception translation is that the service layer only has to deal with exceptions from Spring’s DataAccessException hierarchy, even when using plain JPA in the DAO classes. Another annotation used in ContactDAOImpl is @Autowired
. This is used to autowire the dependency of the ContactDAOImpl on the SessionFactory. net.viralpatel.contact.service
package. File: src/main/java/net/viralpatel/contact/service/ContactService.java package net.viralpatel.contact.service;
import java.util.List;
import net.viralpatel.contact.form.Contact;
public interface ContactService {
public void addContact(Contact contact);
public List<Contact> listContact();
public void removeContact(Integer id);
}
Code language: Java (java)
File: src/main/java/net/viralpatel/contact/service/ContactServiceImpl.java package net.viralpatel.contact.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import net.viralpatel.contact.dao.ContactDAO;
import net.viralpatel.contact.form.Contact;
@Service
public class ContactServiceImpl implements ContactService {
@Autowired
private ContactDAO contactDAO;
@Transactional
public void addContact(Contact contact) {
contactDAO.addContact(contact);
}
@Transactional
public List<Contact> listContact() {
return contactDAO.listContact();
}
@Transactional
public void removeContact(Integer id) {
contactDAO.removeContact(id);
}
}
Code language: Java (java)
In above service layer code, we have created an interface ContactService
and implemented it in class ContactServiceImpl
. Note that we used few Spring annotations such as @Service
, @Autowired
and @Transactional
in our code. These annotations are called Spring stereotype annotations. The @Service
stereotype annotation used to decorate the ContactServiceImpl class is a specialized form of the @Component
annotation. It is appropriate to annotate the service-layer classes with @Service
to facilitate processing by tools or anticipating any future service-specific capabilities that may be added to this annotation. <?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_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Spring3-Hibernate</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Code language: HTML, XML (xml)
Once the web.xml is configured, let us add spring-servlet.xml and jdbc.properties files in /src/main/webapp/WEB-INF folder. File: /src/main/webapp/WEB-INF/jdbc.properties The jdbc.properties file contains database connection information such as database url, username, password, driver class. You may want to edit the driverclass and dialect to other DB if you are not using MySQL.Code language: HTML, XML (xml)jdbc.driverClassName= com.mysql.jdbc.Driver jdbc.dialect=org.hibernate.dialect.MySQLDialect jdbc.databaseurl=jdbc:mysql://localhost:3306/ContactManager jdbc.username=root jdbc.password=testpass
File: /src/main/webapp/WEB-INF/spring-servlet.xmlCode language: HTML, XML (xml)jdbc.driverClassName=oracle.jdbc.driver.OracleDriver jdbc.dialect=org.hibernate.dialect.OracleDialect jdbc.databaseurl=jdbc:oracle:thin:@127.0.0.1:1525:CustomerDB jdbc.username=scott jdbc.password=tiger
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan base-package="net.viralpatel.contact" />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
Code language: HTML, XML (xml)
The spring-servlet.xml file contains different spring mappings such as transaction manager, hibernate session factory bean, data source etc. <?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="net.viralpatel.contact.form.Contact" />
</session-factory>
</hibernate-configuration>
Code language: HTML, XML (xml)
File: /src/main/resources/messages_en.properties label.firstname=First Name
label.lastname=Last Name
label.email=Email
label.telephone=Telephone
label.addcontact=Add Contact
label.menu=Menu
label.title=Contact Manager
label.footer=&copy; ViralPatel.net
Code language: HTML, XML (xml)
package net.viralpatel.contact.controller;
import java.util.Map;
import net.viralpatel.contact.form.Contact;
import net.viralpatel.contact.service.ContactService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class ContactController {
@Autowired
private ContactService contactService;
@RequestMapping("/index")
public String listContacts(Map<String, Object> map) {
map.put("contact", new Contact());
map.put("contactList", contactService.listContact());
return "contact";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addContact(@ModelAttribute("contact")
Contact contact, BindingResult result) {
contactService.addContact(contact);
return "redirect:/index";
}
@RequestMapping("/delete/{contactId}")
public String deleteContact(@PathVariable("contactId")
Integer contactId) {
contactService.removeContact(contactId);
return "redirect:/index";
}
}
Code language: Java (java)
The spring controller defines three methods to manipulate contact manager application. Contact
object using @ModelAttribute
annotation. Also note that the request “/add” is mapped with this method. The request method should also be POST. Once the contact is added in contact list using ContactService
, we redirect to /index page which in turn calls listContacts()
method to display contact list to user. addContact
this method also redirects user to /index page once the contact is removed. One this to note in this method is the way we have mapped request url using @RequestMapping annotation. The url “/delete/{contactId}” is mapped thus whenever user send a request /delete/12, the deleteCotact method will try to delete contact with ID:12.<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring 3 MVC Series - Contact Manager | viralpatel.net</title>
</head>
<body>
<h2>Contact Manager</h2>
<form:form method="post" action="add.html" commandName="contact">
<table>
<tr>
<td><form:label path="firstname"><spring:message code="label.firstname"/></form:label></td>
<td><form:input path="firstname" /></td>
</tr>
<tr>
<td><form:label path="lastname"><spring:message code="label.lastname"/></form:label></td>
<td><form:input path="lastname" /></td>
</tr>
<tr>
<td><form:label path="email"><spring:message code="label.email"/></form:label></td>
<td><form:input path="email" /></td>
</tr>
<tr>
<td><form:label path="telephone"><spring:message code="label.telephone"/></form:label></td>
<td><form:input path="telephone" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="<spring:message code="label.addcontact"/>"/>
</td>
</tr>
</table>
</form:form>
<h3>Contacts</h3>
<c:if test="${!empty contactList}">
<table class="data">
<tr>
<th>Name</th>
<th>Email</th>
<th>Telephone</th>
<th>&nbsp;</th>
</tr>
<c:forEach items="${contactList}" var="contact">
<tr>
<td>${contact.lastname}, ${contact.firstname} </td>
<td>${contact.email}</td>
<td>${contact.telephone}</td>
<td><a href="delete/${contact.id}">delete</a></td>
</tr>
</c:forEach>
</table>
</c:if>
</body>
</html>
Code language: HTML, XML (xml)
Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…
Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…
Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…
1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…
GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…
1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…
View Comments
It'd be better if your example used bean validator also.
Viral,
Great job! I am newer to Spring/Hibernate but can created 1st project by following your example. There is one question:
You created ContactDAO.java and its implementation ContactDAOImpl.java, but ContactService.java and ContactServiceImpl.java are almost copies of ContactDAO.java and ContactDAOImpl.java. Could you explain? I found another sample doesn't have ContactService.java/CntactServiceImpl.java.
Thanks very much
James
Dear Viral,
Firstly, i just want to say thank you. Great post, save me lots of time, but i still got a question below :
I tried to run your project, it work properly, but when i tried to use Maven test command to run unit test cases which are based on AbstractTransactionalJUnit4SpringContextTests, it failed. the test case only pass If i run the test case individually.
I did lots of googling on the internet, someone suggest this is probabaly caused by duplicate copies in Maven Dependencies. I guess it may be caused by conflict between spring-asm-3.0.2.jar and hibernate's asm-3.1.jar, my question is how to exclude one of the duplicate asm jar from the maven dependencies.
I tried to add following into my pom.xml
org.hibernate
asm-all
but dosn't work
can you give me any idea and help me out, thank you very much in advance.
Good article for a spring learner.
To James Chen - In this particular Example ContactService and ContactServiceImpl are almost same but ContactDAO and ContactDAOImpl actually present Data Access specific code and methods, which may be implemented using hibernate, toplink or pure jdbc etc.
What ContactService and ContactServiceImpl present is methods to access data To/from Data Access Layer (i.e. ContactDAO) which is actually independent of data access implementation. There may be a method like addAndListContact() which may be different than in ContactDAO and may call two of ContactDAO's method.
I think u got my point.
Thanks
good Example!.
I want to make simple MVC web
this example used [action, service, dao] 3steps.
I want to only [action + dao] except service layer
because my web is so simple never want service layer
I just want call dao method in action Controller
sadly I can't find [action +dao] sample in google..
how can I that? thank's any answer.
Hi,
Thanks for this tutorial. I made this as basis for my first spring-hibernate annotations project. However, I have encountered an error when I deployed it on Tomcat. The error is:
Could not initialize class org.hibernate.cfg.AnnotationConfiguration
I have the following jar files on my WEB-INF/lib, but still the error persist.
dom4j-1.6.1.jar
hibernate-annotations-3.4.0.GA.jar
hibernate-core-3.3.1.GA.jar
hibernate-commons-annotations-3.1.0.GA.jar
log4j-1.2.15.jar
slf4j-api-1.5.6.jar
slf4j-log4j12-1.5.6.jar
Did I miss some jar or configuration files?
Your help will be greatly appreciated.
Thanks
I have tried with with eclipse but I am getting the following error:
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/spring-servlet.xml]; nested exception is java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor
Is there anything specific that I am supposed to do? I can send you the files but they are exactly as you have in your download part.
Great tutorial, great app. Well, except for the fact that the source code does not compile and does not run (even after adding missing dependencies) under Tomcat 6 :-(
I have this error:
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private springapp.dao.ContactService springapp.web.ContactController.contactService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [springapp.dao.ContactService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
any ideas?
very nice example Thanks alot.,
@Selvan - Thanks :)