Paul Sydney has posted 1 posts at DZone. View Full User Profile

Adding CRUD Capability to Spring MVC

12.09.2010
| 15341 views |
  • submit to reddit

This article is intended for people who are interested in Spring and Hibernate, especially those who are new to the technology. Create, Read, Update and Delete capabilities are essential to a web based application. In this article, I'll be sharing how to add these capabilities to your Spring MVC application. I will be adding the CRUD (Create, Read/Retrieve, Update, Delete) capbility, which will be the operations performed on the database records prior to a certain domain object. We will be using Hibernate as our ORM and our database will be MySQL.

Advanced programmers are also welcome to comment and post suggestions in this article. I accept anything, whether it's positive or negative. :-)

Let us begin!

First, let us create a a Spring configuration resource named “SampleSpringMVC-dao.xml”

<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright : adobocode.com , 2010 -->
<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:jee="http://www.springframework.org/schema/jee" 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-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="paul.sydney.dataaccess" />
<tx:annotation-driven />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/my_dummy_db" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sessionFactoryGrabber" factory-bean="entityManagerFactory"
factory-method="getSessionFactory" />
<bean id="personDao" class="paul.sydney.dataaccess.PersonDaoImpl">
<property name="sessionFactory" ref="sessionFactoryGrabber" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryGrabber" />
</bean>
</beans>

 Let us then create a “personForm.jsp”  (note that the Save and Delete button has the same name and they only differ in value):

<!-- Copyright : adobocode.com , 2010 -->
<%@ page language="java" session="false"
contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Adobocode : Sample Spring MVC using Forms</title>
</head>
<body>
<h2>Adobocode : Person Form</h2>
<form:form modelAttribute="person">
<form:hidden path="id" />
<fieldset>
<table>
<tr>
<td>Name</td>
<td><form:input path="name" /><form:errors path="name" /></td>
</tr>
<tr>
<td>Age</td>
<td><form:input path="age" /><form:errors path="age" /></td>
</tr>
<tr>
<td>Address</td>
<td><form:input path="address" /><form:errors path="address" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" id="save" name="action" value="Save" />
<input type="submit" id="delete" name="action" value="Delete" /> <input
type="submit" name="_eventId_cancel" value="Cancel" /></td>
</tr>
</table>
</fieldset>
</form:form>
</body>
</html>

 Now, let us create and annotate our model class Person with JPA:

package paul.sydney.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Copyright : adobocode.com , 2010
*
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*/
@Entity
@Table(name = "person")
public class Person {
@Id
@GeneratedValue
@Column(name = "person_id")
private int id;
@Column(name = "person_name")
private String name;
@Column(name = "person_age")
private int age;
@Column(name = "person_address")
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}

 Now let us create our DAO layer. First, let us create an interface “PersonDao”

package paul.sydney.dao;
import java.util.List;
import paul.sydney.model.Person;
/**
* Copyright : adobocode.com , 2010
*
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*/
public interface PersonDao {
public void savePerson(Person person);
public void deletePerson(Person person);
public List retrieveAll();
public Person retrievePerson(int id);
}

 and it's implementing class:

package paul.sydney.dataaccess;
import java.util.List;
import org.hibernate.LockMode;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;
import paul.sydney.dao.PersonDao;
import paul.sydney.model.Person;
/**
* Copyright : adobocode.com , 2010
*
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*/
@Repository("personDao")
public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao {
public PersonDaoImpl() {
super();
}
@Override
public void deletePerson(Person person) {
getHibernateTemplate().delete(person, LockMode.NONE);
}
@Override
public List retrieveAll() {
List personList = getHibernateTemplate().loadAll(Person.class);
return personList;
}
@Override
public Person retrievePerson(int id) {
return (Person) getHibernateTemplate().get(Person.class, id);
}
@Override
public void savePerson(Person person) {
getHibernateTemplate().saveOrUpdate(person);
}
}

 and the business modules that relies on those DAO layer:

package paul.sydney.service;
import java.util.List;
import paul.sydney.model.Person;
/**
* Copyright : adobocode.com , 2010
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*/
public interface IDummyService {
public List getDummyList();
public Person retrievePerson(int id);
public void savePerson(Person person);
public void deletePerson(Person person);
}

 and it's implementing class:

package paul.sydney.service;
import paul.sydney.dao.PersonDao;
import paul.sydney.model.Person;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Propagation;
/**
* Copyright : adobocode.com , 2010
*
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*/
@Service("dummyService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = false)
public class DummyService implements IDummyService {
@Autowired
private PersonDao personDao;
public List getDummyList() {
return this.personDao.retrieveAll();
}
public Person retrievePerson(int id) {
return this.personDao.retrievePerson(id);
}
public void savePerson(Person person) {
this.personDao.savePerson(person);
}
@Override
public void deletePerson(Person person) {
this.personDao.deletePerson(person);
}
}

and finally the Controller which will consume the service/business layer:

package paul.sydney.controller;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import paul.sydney.controller.validation.PersonValidator;
import paul.sydney.model.Person;
import paul.sydney.service.IDummyService;
/**
* PersonForm class, form controller for the 'personForm.jsp'
* Copyright : www.adobocode.com , 2010
*
* @author Paul Sydney Orozco | xtrycatchx@gmail.com
*
*/
@Controller
@RequestMapping("/personForm.htm")
@SessionAttributes("person")
public class PersonForm {
@Autowired
private IDummyService dummyService;
private final String SAVE_ACTION = "Save";
private final String PARAM_ACTION = "action";
private final String PERSON_ATTRIBUTE = "person";
private final String PERSON_ID = "personId";
private final String PERSON_FORM = "personForm";
private final String PERSON_DISPLAY = "redirect:personDisplay.htm";
@RequestMapping(method = RequestMethod.GET)
public Person setupForm(
@RequestParam(value = PERSON_ID, required = false) Integer id) {
if (id == null) {
return new Person();
} else {
return this.dummyService.retrievePerson(id);
}
}
@RequestMapping(method = RequestMethod.POST)
public String save(@ModelAttribute(PERSON_ATTRIBUTE) Person person,
BindingResult result, SessionStatus status,
@RequestParam(PARAM_ACTION) String request) {
if (SAVE_ACTION.equals(request)) {
new PersonValidator().validate(person, result);
if (result.hasErrors()) {
return PERSON_FORM;
} else {
this.dummyService.savePerson(person);
status.setComplete();
return PERSON_DISPLAY;
}
} else {
this.dummyService.deletePerson(person);
status.setComplete();
return PERSON_DISPLAY;
}
}
}

These are the things needed  in your existing Spring MVC application in order to cater for CRUD capability. Hope you guys learn something.

For the basic Spring MVC Tutorial : Basic Spring Tutorial

For adding validations for Spring Forms : Adding Validations to Spring MVC forms

More stuff can be found at : www.adobocode.com

 

Published at DZone with permission of its author, Paul Sydney Orozco.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mustafa Dasgin replied on Thu, 2010/12/09 - 7:48am

Hi Paul,
With <context:annotation-config /> in context.xml, PersistenceAnnotationBeanPostProcessor is also implicitly included. You are not required explicitly write it.
And by adding

@PersistenceContext
private EntityManager entityManager;

in DAO class you can use entityManager like entityManager.persist(person)
so you don't need to use HibernateDaoSupport interface and sessionFactoryGrabber bean definition. For more info see: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/orm.html

Good article, thanks..

Philopator Ptolemy replied on Thu, 2010/12/09 - 8:54am

Spring Roo is especially well suited for CRUD apps. Using Roo this whole app can be done with about 10-15 commands.

It generate all Spring MVC artifacts including configs.

Richard Kennard replied on Thu, 2010/12/09 - 8:56pm

Paul,

May I humbly suggest Metawidget (http://metawidget.org) may be able to help reduce your personForm.jsp? It is like Hibernate (an ORM) but for the UI (so, an OIM if you will) and comes with Spring MVC integration. It is designed to slot into your existing app with minimal disruption to your architecture.

If you get chance to try it, I'd be most interested to hear how you go.

Regards,

Richard.

Tony Childs replied on Fri, 2010/12/10 - 12:15pm

Metawidget looks interesting, but your live demo is broken. What a shame.

Richard Kennard replied on Fri, 2010/12/10 - 3:46pm

Tony,

Thanks for taking a look at Metawidget. Yes, we have some problems around use of a Groovy console in an applet in some environments (usual applet deployment stuff). They aren't specifically Metawidget-related, but I realise it can give a bad first impression.

You could greatly help by letting me know what environment you're using and what error message you're seeing. Also, could you try downloading the Metawidget binary distribution and checking it works okay on your platform? Please let me know at support@metawidget.org.

Regards,

Richard.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.