CustomMenu

Saturday, February 15, 2014

Spring MVC 4 - Hibernate 4 CRUD

This example builds on the last post, Spring MVC 4 - Java Config, where Spring Java configuration files replaced the standard Spring MVC template XML files created by STS in Eclipse. In addition, this code shows an end-to-end example of:

MySQL -> Hibernate -> Spring MVC -> JSP

A link to the code on GitHub is provided at the bottom of this post.  Here is a summary of the steps to complete the end to end use case:
1. Create a table in your database  using the SQL below.  This SQL creates a simple table with three columns.  This table will hold our trade strategies.  The type would contain an option trade type, and the name would contain a specific sub type.  For example, type could be "iron condor", and name could be "hedged high prob".
CREATE TABLE `strategy` (
    `ID` INT(6) UNSIGNED NOT NULL AUTO_INCREMENT,
    `TYPE` VARCHAR(20) NOT NULL,
    `NAME` VARCHAR(20) NOT NULL,
    PRIMARY KEY (`ID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=8;

2. Create the Spring database configuration file to configure the Spring and Hibernate connectivity to our database where we created the strategy table.
package com.dtr.oas.config;

import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan("com.dtr.oas")
@PropertySource("classpath:database.properties")
public class DatabaseConfig {

    private static final String PROPERTY_NAME_DATABASE_DRIVER   = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL      = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
 
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
    
 @Resource
 private Environment env;
 
 @Bean
 public DataSource dataSource() {
  DriverManagerDataSource dataSource = new DriverManagerDataSource();
  dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
  dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
  dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
  dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
  return dataSource;
 }
 
 private Properties hibProperties() {
  Properties properties = new Properties();
  properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
  properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
  return properties; 
 }
 
 @Bean
 public HibernateTransactionManager transactionManager() {
  HibernateTransactionManager transactionManager = new HibernateTransactionManager();
  transactionManager.setSessionFactory(sessionFactory().getObject());
  return transactionManager;
 }
 
 @Bean
 public LocalSessionFactoryBean sessionFactory() {
  LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
  sessionFactoryBean.setDataSource(dataSource());
  sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
  sessionFactoryBean.setHibernateProperties(hibProperties());
  return sessionFactoryBean;
 }
}

3. Create the properties file used by the database configuration java file.  This file will contain the details about our specific database.  This file is located in the resources directory under main (not the one in webapp).
#DB properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://192.168.0.100:3306/oas
db.username=root
db.password=password

#Hibernate Configuration:
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql=true
entitymanager.packages.to.scan=com.dtr.oas.model

4. Update the Initializer.java to load the new database configuration file.  The only change to this code was the addition of the DatabaseConfig.class entry in the getRootConfigClasses method:
package com.dtr.oas.config;

import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.dtr.oas.config.DatabaseConfig;

@Order(1)
public class Initializer extends
  AbstractAnnotationConfigDispatcherServletInitializer {

 @Override
 protected Class<?>[] getRootConfigClasses() {
  return new Class[] { DatabaseConfig.class };
 }

 @Override
 protected Class<?>[] getServletConfigClasses() {
  return new Class<?>[] { WebAppConfig.class };
 }

 @Override
 protected String[] getServletMappings() {
  return new String[] { "/" };
 }

}

5. We now create the standard model, DAO, and service layers.  The model/entity class is first:
package com.dtr.oas.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="strategy")
public class Strategy {
 
 @Id
 @GeneratedValue
 private Integer id;
 private String type;
 private String name;

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}

6. The DAO layer has an interface and an implementation:
package com.dtr.oas.dao;

import java.util.List;
import com.dtr.oas.model.Strategy;

public interface StrategyDAO {

    public void addStrategy(Strategy strategy);
    public Strategy getStrategy(int id);
    public void updateStrategy(Strategy strategy);
    public void deleteStrategy(int id);
    public List<Strategy> getStrategies();
    
}
package com.dtr.oas.dao;

import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.dtr.oas.model.Strategy;

@Repository
public class StrategyDAOImpl implements StrategyDAO {

 @Autowired
 private SessionFactory sessionFactory;

 private Session getCurrentSession() {
  return sessionFactory.getCurrentSession();
 }

 public void addStrategy(Strategy strategy) {
  getCurrentSession().save(strategy);
 }

 public void updateStrategy(Strategy strategy) {
  Strategy strategyToUpdate = getStrategy(strategy.getId());
  strategyToUpdate.setName(strategy.getName());
  strategyToUpdate.setType(strategy.getType());
  getCurrentSession().update(strategyToUpdate);
 }

 public Strategy getStrategy(int id) {
  Strategy strategy = (Strategy) getCurrentSession().get(Strategy.class, id);
  return strategy;
 }

 public void deleteStrategy(int id) {
  Strategy strategy = getStrategy(id);
  if (strategy != null)
   getCurrentSession().delete(strategy);
 }

 @SuppressWarnings("unchecked")
 public List<Strategy> getStrategies() {
  return getCurrentSession().createQuery("from Strategy").list();
 }

}

7. The service layer contains an interface and an implementation:
package com.dtr.oas.service;

import java.util.List;
import com.dtr.oas.model.Strategy;

public interface StrategyService {

    public void addStrategy(Strategy strategy);
    public Strategy getStrategy(int id);
    public void updateStrategy(Strategy strategy);
    public void deleteStrategy(int id);
    public List<Strategy> getStrategies();

}
package com.dtr.oas.service;

import java.util.List;
import com.dtr.oas.dao.StrategyDAO;
import com.dtr.oas.model.Strategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class StrategyServiceImpl implements StrategyService {

 @Autowired
 private StrategyDAO strategyDAO;

 @Override
 public void addStrategy(Strategy strategy) {
  strategyDAO.addStrategy(strategy);
 }

 @Override
 public void updateStrategy(Strategy strategy) {
  strategyDAO.updateStrategy(strategy);
 }

 @Override
 public Strategy getStrategy(int id) {
  return strategyDAO.getStrategy(id);
 }

 @Override
 public void deleteStrategy(int id) {
  strategyDAO.deleteStrategy(id);
 }

 @Override
 public List<Strategy> getStrategies() {
  return strategyDAO.getStrategies();
 }

}

8. The controller layer is next. We need to replace the default controller generated by STS and also create a controller for the strategy service.
package com.dtr.oas.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LinkController {

 @RequestMapping(value="/")
 public ModelAndView mainPage() {
  return new ModelAndView("home");
 }

 @RequestMapping(value="/index")
 public ModelAndView indexPage() {
  return new ModelAndView("home");
 }

}
package com.dtr.oas.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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;
import org.springframework.web.servlet.ModelAndView;
import com.dtr.oas.model.Strategy;
import com.dtr.oas.service.StrategyService;

@Controller
@RequestMapping(value="/strategy")
public class StrategyController {

 @Autowired
 private StrategyService strategyService;
 
 @RequestMapping(value="/add", method=RequestMethod.GET)
 public ModelAndView addStrategyPage() {
  ModelAndView modelAndView = new ModelAndView("strategy-add");
  modelAndView.addObject("strategy", new Strategy());
  return modelAndView;
 }
 
 @RequestMapping(value="/add", method=RequestMethod.POST)
 public ModelAndView addingStrategy(@ModelAttribute Strategy strategy) {
  ModelAndView modelAndView = new ModelAndView("home");
  strategyService.addStrategy(strategy);
  String message = "Strategy was successfully added.";
  modelAndView.addObject("message", message);
  return modelAndView;
 }
 
 @RequestMapping(value="/list")
 public ModelAndView listOfStrategies() {
  ModelAndView modelAndView = new ModelAndView("strategy-list");
  List<strategy> strategies = strategyService.getStrategies();
  modelAndView.addObject("strategies", strategies);
  return modelAndView;
 }
 
 @RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
 public ModelAndView editStrategyPage(@PathVariable Integer id) {
  ModelAndView modelAndView = new ModelAndView("strategy-edit");
  Strategy strategy = strategyService.getStrategy(id);
  modelAndView.addObject("strategy",strategy);
  return modelAndView;
 }
 
 @RequestMapping(value="/edit/{id}", method=RequestMethod.POST)
 public ModelAndView edditingStrategy(@ModelAttribute Strategy strategy, @PathVariable Integer id) {
  ModelAndView modelAndView = new ModelAndView("home");
  strategyService.updateStrategy(strategy);
  String message = "Strategy was successfully edited.";
  modelAndView.addObject("message", message);
  return modelAndView;
 }
 
 @RequestMapping(value="/delete/{id}", method=RequestMethod.GET)
 public ModelAndView deleteStrategy(@PathVariable Integer id) {
  ModelAndView modelAndView = new ModelAndView("home");
  strategyService.deleteStrategy(id);
  String message = "Strategy was successfully deleted.";
  modelAndView.addObject("message", message);
  return modelAndView;
 }
}

9. The last step is to create the JSPs. We will replace the home.jsp with a new one, and and the CRUD JSPs:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"  pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Home page</title>
</head>
<body>
<h1>Home page</h1>
<p>
${message}<br/>
<a href="${pageContext.request.contextPath}/strategy/add.html">Add New Strategy</a><br/>
<a href="${pageContext.request.contextPath}/strategy/list.html">Strategy list</a><br/>
</p>
</body>
</html>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"  pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>List of Strategies</title>
</head>
<body>
<h1>List of strategies</h1>
<p>Here you can see the list of the strategies, edit them, remove or update.</p>
<table class="table table-striped" border="1px" cellpadding="0" cellspacing="0" >
<thead>
<tr>
<th width="10%">id</th><th width="15%">name</th><th width="10%">type</th><th width="10%">actions</th>
</tr>
</thead>
<tbody>
<c:forEach var="strategy" items="${strategies}">
<tr>
 <td>${strategy.id}</td>
 <td>${strategy.name}</td>
 <td>${strategy.type}</td>
 <td>
 <a href="${pageContext.request.contextPath}/strategy/edit/${strategy.id}.html">Edit</a><br/>
 <a href="${pageContext.request.contextPath}/strategy/delete/${strategy.id}.html">Delete</a><br/>
 </td>
</tr>
</c:forEach>
</tbody>
</table>

<p><a href="${pageContext.request.contextPath}/index.html">Home page</a></p>

</body>
</html>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Add strategy page</title>
</head>
<body>
<h1>Add strategy page</h1>
<p>Here you can add a new strategy.</p>
<form:form method="POST" commandName="strategy" action="${pageContext.request.contextPath}/strategy/add.html">
<table>
<tbody>
 <tr>
  <td>Name:</td>
  <td><form:input path="name" /></td>
 </tr>
 <tr>
  <td>Type:</td>
  <td><form:input path="type" /></td>
 </tr>
 <tr>
  <td><input type="submit" value="Add" /></td>
  <td></td>
 </tr>
</tbody>
</table>
</form:form>

<p><a href="${pageContext.request.contextPath}/index.html">Home page</a></p>
</body>
</html>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Edit strategy page</title>
</head>
<body>
<h1>Edit strategy page</h1>
<p>Here you can edit the existing strategy.</p>
<p>${message}</p>
<form:form method="POST" commandName="strategy" action="${pageContext.request.contextPath}/strategy/edit/${strategy.id}.html">
<table>
<tbody>
 <tr>
  <td>Name:</td>
  <td><form:input path="name" /></td>
 </tr>
 <tr>
  <td>Type:</td>
  <td><form:input path="type" /></td>
 </tr>
 <tr>
  <td><input type="submit" value="Edit" /></td>
  <td></td>
 </tr>
</tbody>
</table>
</form:form>

<p><a href="${pageContext.request.contextPath}/index.html">Home page</a></p>
</body>
</html>

10. After all of these steps, you should have a directory structure like the one below:


11. Right-click on the project -> Run As -> Run On Server and follow the steps in the wizard.  When you run this project on the server, you should see a page similar to the one below.


Code at GitHub: https://github.com/dtr-trading/spring-ex02

Lastly, if you are looking for another example of this process, see the post:
http://fruzenshtein.com/spring-mvc-hibernate-maven-crud/.

29 comments:

Anonymous said...

Very good tutorial! You saved my day

I have only two typo errors that drove me crazy:

strategy-edit.jsp (line 15) : action="${pageContext.request.contextPath}/strategy/edit/${strategy.id}.html"

${team.id} => ${strategy.id}

and

StrategyController.java (line 40) : List strategies = strategyService.getStrategies();

List => List


Thanks


Anonymous said...

Excellent. I'm glad to hear you found this post useful!

Thanks,
Dave

Anonymous said...

Thanks for this tutorial
i have a question why you didn't use the web.xml in your project !!

Dave R. said...

Starting somewhere around Spring version 3.1, the options was provided to use either Java based configuration or XML based configuration...or a mix of the two. It's really personal preference whether you use one or the other.

I have scars from all of the XML config files in J2EE apps in the late '90s and early 2000s, so I tend to eliminate XML config when ever I can...it is a personal preference.

If you want to learn more about this configuration options in Spring MVC 4.x, take a look at:
http://docs.spring.io/spring/docs/4.0.3.RELEASE/spring-framework-reference/htmlsingle/#mvc-config

For information on the web.xml specifically, take a look at this api link:
http://docs.spring.io/spring/docs/4.0.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html

Unknown said...

Very good example...Thanks.

I have one doubt here in strategy-edit.jsp in action path you are passing "team.id" what is team here and how it is populated with strategy id?

Thanks in advance...

Unknown said...

i think its not team.id it should be strategy.id
Thanks

Dave R. said...

Siva - good catch!

I'm not sure how I checked that code into Github and entered it into this blog entry. This code clearly could not function in its current form. I've updated the code in both Github and this blog.

Thanks!

Dave

Byan Prihandana Jati said...

thanks , works like a charm , but i need to increase my server timeout into 60 secs.

Also thanks for the git repo :) , i could build this project with no time

Dave R. said...

You're welcome. Happy to hear the code is working for you!

Anonymous said...

This example doesn't have web.xml file. Can you please upload it for us?

Unknown said...

This example doesn't have web.xml file. Can you please upload it for us?

Dave R. said...

Hi Manivannan,

The short answer is that starting with Spring MVC 3.2/ Spring 3.2, there is support for Servlet 3.0. I'm running on Tomcat 7.0.50 and this version supports Servlet 3.0. With Servlet 3.0, the web.xml is not required if you use the proper annotations in your configuration files. Take a look at the links below for much more detail:

Spring MVC 4.0 web.xml info: http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/mvc.html

StackOverflow no web.xml: http://stackoverflow.com/questions/15008126/spring-mvc-and-servlets-3-0-do-you-still-need-web-xml

ZeroTurnAround no web.xml: http://zeroturnaround.com/rebellabs/your-next-java-web-app-less-xml-no-long-restarts-fewer-hassles-part-1/

Tomcat Servlet Spec Support: http://tomcat.apache.org/whichversion.html

Servlet 3.0 info: https://today.java.net/pub/a/today/2008/10/14/introduction-to-servlet-3.html#annotations-vs-deployment-descriptor

I hope this answers your question. Please let me know if you have any other questions.

Thanks,
Dave

Anonymous said...

Good job. You seem to be the only one one so far who can provide a tutorial and source that actually works. Thanks!!!

Dave R. said...

Thank you for the comment...I appreciate the compliment!

Dave

Unknown said...

Hello sir,
after running the program how do i access the pages
http://localhost:8080/spring-ex02/home.jsp
http://localhost:8080/spring-ex02/strategy-list.jsp

please help

Dave R. said...

The extensions should be .html rather than .jsp.

Also, when I run this application in Eclipse, using a configured Tomcat instance, a browser opens in the Eclipse IDE with the default page loaded.

I'm not sure if I answered your question, but if you have more questions/details I will try my best to answer them.

Thanks,
Dave

Anonymous said...

excellent example using java configuration... great job!!!!!

Dave said...

Thank you for your feedback...much appreciated!

Dave

Arvind said...

Nice Article. Useful to understand Spring 4 + Hibernate integration.

Dave R. said...

Thank you for the comment...I appreciate your feedback!

Dave

Jay Min said...

The public type StrategyDAO must be defined in its own file StrategyDao.java how solve this error.

Jay Min said...

I write your program.It has not compile error.But when i run
HTTP Status 404 - /spring-ex02/

type Status report

message /spring-ex02/

description The requested resource is not available.

Apache Tomcat/8.0.30

Jay Min said...

when I run your project,I found 404.

Jay Min said...

hey please response my letter.

Unknown said...

This is a poor example as long as you are using an entity in the controller layer, which is extremely discourage

Dave R. said...

Javier, agreed...please read the subsequent articles where the DTO packaged is introduced, and access to the entity layer is restricted.

Thanks,
Dave

Dave R. said...

Hi Jay Min,

Please provide more detail regarding your issue. You did not provide enough detail about the error you are experiencing and your configuration.

Thanks,
Dave

Unknown said...

Looking forward to read all your artlces as I considere this website a good tool for developers. I forgot to say thank you in my previous message :)

Unknown said...

thanks very much . I love you and love this project. Thanks agiang

Post a Comment