Warning: mysql_query(): Unable to save result set in /data02/c3398167/public_html/vsf-blog/wp-content/plugins/vsf-simple-block/vsf_simple_block_check.php on line 58
Spring MVC 3.0.5 with Hibernate and Maven project » Victoria's blog
Dec 052010
 

I’ve just started trying to piece together a Spring MVC project with Hibernate and Maven in Eclipse. So far it has been VERY frustrating as Eclipse wasn’t publishing the app with the lib files. That took over an hour of my time up and I haven’t yet managed to get it to run. I will update the following when I finally get it working, but here are the basics of what I have so far Ok, I’ve got it working finally. Turns out there are some unusual settings files that contain relevant paths for web app deployment. The following have been updated and should work:

MyObject.java

package uk.co.vsf.MyApp.database.beans;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class MyObject
{
	@Id
	private Integer myId;

	public MyObject(Integer myId)
	{
		this.myId = myId;
	}

	public void setMyId(Integer myId)
	{
		this.myId = myId;
	}

	public Integer getMyId()
	{
		return myId;
	}
}


AbstractDAO.java

package uk.co.vsf.MyApp.database.dao;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

class AbstractDAO<T> extends HibernateDaoSupport implements IDAO<T>
{
	protected final Log log = LogFactory.getLog(getClass());

	protected Class<T> entityClass;
	protected String tableName;
	protected String orderFieldName;

	public AbstractDAO(final String tableName, final String orderFieldName, final Class<T> entityClass)
	{
		this.tableName = tableName;
		this.orderFieldName = orderFieldName;
		this.entityClass = entityClass;
	}

	/** {@inheritDoc} */
	public void save(final T transientInstance)
	{
		log.debug("About to save object of type " + entityClass);
		try
		{
			getHibernateTemplate().save(transientInstance);
			log.debug("Saved");
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to save object of type " + entityClass, re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public void delete(final T persistentInstance)
	{
		log.debug("About to delete instance of " + entityClass);
		try
		{
			getHibernateTemplate().delete(persistentInstance);
			log.debug("Delete successful");
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to delete instance of " + entityClass, re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public T findById(final String id)
	{
		log.debug("About to find instance of " + entityClass + " with id: " + id);
		try
		{
			final T instance = (T) getHibernateTemplate().get(this.entityClass, id);
			return instance;
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to find instance of " + entityClass + " with id: " + id, re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	/** {@inheritDoc} */
	public List<T> findAll()
	{
		log.debug("About to find all instances of " + entityClass);
		try
		{
			String queryString = "FROM " + tableName;
			queryString += " ORDER BY " + orderFieldName;
			return getHibernateTemplate().find(queryString);
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to find all instances of " + entityClass, re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	/** {@inheritDoc} */
	public int getRowCount()
	{
		log.debug("About to get a row count of table " + tableName);
		try
		{
			final Criteria criteria = this.getSession(false).createCriteria(this.entityClass);
			criteria.setProjection(Projections.rowCount());
			final List<Integer> results = criteria.list();
			return results.get(0);
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to get row count of table " + tableName, re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public T merge(final T detachedInstance)
	{
		log.debug("Merging instance of type " + entityClass);
		try
		{
			final T result = (T) getHibernateTemplate().merge(detachedInstance);
			log.debug("Merged succesfully");
			return result;
		}
		catch ( final RuntimeException re )
		{
			log.error("Merge of instance type " + entityClass + " failed", re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public void deleteAll()
	{
		log.debug("About to delete all records from the " + tableName);
		try
		{
			// flush all changes to the database to avoid issues when deleting.
			this.getHibernateTemplate().flush();
			final int rows = this.getHibernateTemplate().bulkUpdate("delete from " + tableName);
			log.debug("successfully " + rows + " deleted");
			this.getHibernateTemplate().clear();
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to delete all rows from " + tableName, re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public void flushAndClear()
	{
		try
		{
			flush();
			this.getHibernateTemplate().clear();
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to flush and clear the cache", re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public void flush()
	{
		try
		{
			this.getHibernateTemplate().flush();
		}
		catch ( final RuntimeException re )
		{
			log.error("Failed to flush the cache", re);
			throw re;
		}
	}

	/** {@inheritDoc} */
	public T update(final T instance)
	{
		return merge(instance);
	}

	/**
	 * Limits the number of results given the start position and the number of results required.
	 *
	 * @param criteria
	 *            criteria object to apply limit to
	 * @param start
	 *            the start position of the limit, E.g. row 15 = 15
	 * @param fetchSize
	 *            the amount to fetch, E.g. 20 rows.
	 */
	protected void limitCriteria(final Criteria criteria, final int start, final int fetchSize)
	{
		criteria.setFirstResult(start);
		criteria.setFetchSize(fetchSize);
		criteria.setMaxResults(fetchSize);
	}
}

IDAO.java

package uk.co.vsf.MyApp.database.dao;

import java.util.List;

public interface IDAO<T>
{
	/**
	 * Save an instance to the table.
	 *
	 * @param instance
	 *            row to add to table
	 */
	void save(T instance);

	/**
	 * Delete the supplied instance from the database table.
	 *
	 * @param instance
	 *            to delete from the table
	 */
	void delete(T instance);

	/**
	 * Finds the specific instance in the database which matches the 'id' passed in.
	 *
	 * @param id
	 *            Id to find in database
	 * @return the instance with the given id, or <code>null</code> if it is not found.
	 */
	T findById(String id);

	/**
	 * Find all instances in a table. The SQL equivalent is - select * from table.
	 *
	 * @return List of table rows
	 */
	List<T> findAll();

	/**
	 * Returns the row count for the particular table.
	 *
	 * @return the number of rows in the table
	 */
	int getRowCount();

	/**
	 * Merge changes.
	 */
	T merge(T detachedInstance);

	/**
	 * Delete all instances from the database. Equivalent to delete from table.
	 */
	void deleteAll();

	/**
	 * Flushes the changes in the cache to the database and clears the cache. If any stored
	 * procedures or native sql code is used, this must be called first.
	 */
	void flushAndClear();

	/**
	 * Flushes the changes in the cache to the database.
	 * ALWAYS run before a stored procedure!
	 */
	void flush();

	/**
	 * Update the instance.
	 */
	T update(T instance);
}

MyDAO.java

package uk.co.vsf.MyApp.database.dao;

import uk.co.vsf.MyApp.database.beans.MyObject;

public class MyDAO extends AbstractDAO<MyObject>
{
	public MyDAO()
	{
		super("MyObject", "id", MyObject.class);
	}

	/*
	 * final Criteria criteria = getSession(false).createCriteria(MyObject.class);
	 * criteria.createAlias("myObjectsReferenceEntityName", "tableLink1");
	 * criteria.add(Restrictions.eq("tableLink1.myField2", 1));
	 * criteria.add(Restrictions.isNotNull("field1"));
	 * criteria.setProjection(Projections.rowCount());
	 * final List<MyObject> myObjects = criteria.list();
	 */
}

IMyController.java

package uk.co.vsf.MyApp.presentation.controller;

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

public interface IMyController
{
	@RequestMapping(value = "/page1.html")
	ModelAndView page1(final String order, final String direction);

	@RequestMapping(value = "/page2.html")
	ModelAndView page2();
}

IMyController.java

package uk.co.vsf.MyApp.presentation.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import uk.co.vsf.MyApp.database.dao.MyDAO;

@Controller
public class MyController implements IMyController
{
	@Autowired
	private MyDAO myDAO;

	public void setMyDAO(final MyDAO myDAO)
	{
		this.myDAO = myDAO;
	}

	public ModelAndView page1(@RequestParam(value = "order", required = false) final String order,
			@RequestParam(value = "direction", required = true) final String direction)
	{
		return null;
	}

	/** {@inheritDoc} */
	public ModelAndView page2()
	{
		final ModelAndView mav = new ModelAndView("mypage");
		mav.addObject("myvar", 1);
		mav.addObject("myobjects", myDAO.findAll());

		return mav;
	}
}

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

        <property name="show_sql">true</property>

        <mapping class="uk.co.vsf.MyApp.database.beans.MyObject"/>
    </session-factory>
</hibernate-configuration>

log4j.properties

log4j.rootCategory=ERROR, FILEROLLER, CONSOLE

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[MyApp] %d{dd MMM yyyy HH:mm:ss,SSS} %p: [%t %C{1}.%M(%L)] : %m%n

log4j.appender.FILEROLLER=org.apache.log4j.RollingFileAppender
log4j.appender.FILEROLLER.layout=org.apache.log4j.PatternLayout
log4j.appender.FILEROLLER.layout.ConversionPattern=[MyApp] %d{dd MMM yyyy HH:mm:ss,SSS} %p: [%t %C{1}.%M(%L)] : %m%n
log4j.appender.FILEROLLER.File=${catalina.home}/logs/myApp.log
log4j.appender.FILEROLLER.MaxFileSize=105MB
log4j.appender.FILEROLLER.MaxBackupIndex=3
log4j.appender.FILEROLLER.threshold=DEBUG

# If programmed properly the most messages would be at DEBUG and the least at FATAL.
#log4j.logger.com.tripLog=INFO

log4j.logger.uk.co.vsf.MyApp=DEBUG

mypage.jsp

<html>

	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
				<%
					final String TEST_VAR = "myVAR";
				%>

	</head>
	<body>
	${myobjects}

	</body>
</html>

applicationContext-datasource.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

	    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	    <property name="url" value="jdbc:mysql://localhost:3306/scales"/>
	   	<property name="username" value="root"/>
	    <property name="password" value=""/>

	    <property name="maxActive" value="25"/>
	    <property name="maxIdle" value="10"/>
	    <property name="maxWait" value="-1"/>
	    <property name="removeAbandoned" value="true"/>
	    <property name="removeAbandonedTimeout" value="60"/>
	    <property name="logAbandoned" value="true"/>
	    <property name="accessToUnderlyingConnectionAllowed" value="true"/>
	    <property name="initialSize" value="1"/>
	</bean>

</beans>

applicationContext.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"
    xsi:schemaLocation="

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-3.0.xsd


http://www.springframework.org/schema/tx

    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">

	<bean id="sessionFactory"
	    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
	    <property name="dataSource" ref="dataSource"/>
	    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	    <property name="sessionFactory" ref="sessionFactory"/>
	</bean>

	<tx:annotation-driven transaction-manager="transactionManager"/>

	<!--<bean id="myManager" class="uk.co.v-s-f.myApp.MyManager" autowire="byType"/>-->

	<bean id="myDAO" class="uk.co.vsf.MyApp.database.dao.MyDAO" autowire="byType">
	    <property name="sessionFactory">
	        <ref local="sessionFactory"/>
	    </property>
	</bean>
</beans>

myApp-servlet.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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	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/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

	<context:annotation-config />

	<context:component-scan base-package="uk.co.vsf.MyApp" />

	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
	<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/webpages/" />
		<property name="suffix" value=".jsp" />
	</bean>

</beans>

web.xml

<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/applicationContext.xml
			/WEB-INF/applicationContext-datasource.xml
		</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>myApp</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>detectAllViewResolvers</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>myApp</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>

</web-app>

.classpath

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
	<classpathentry excluding="**/*.java" kind="src" output="target/classes" path="src/main/resources"/>
	<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
	<classpathentry excluding="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
	<classpathentry exported="true" kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER">
		<attributes>
			<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
		</attributes>
	</classpathentry>
	<classpathentry exported="true" kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
	<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
	<classpathentry kind="output" path="target/classes"/>
</classpath>

.project

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
	<name>myApp</name>
	<comment></comment>
	<projects>
	</projects>
	<buildSpec>
		<buildCommand>
			<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.eclipse.wst.common.project.facet.core.builder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.eclipse.jdt.core.javabuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.eclipse.wst.validation.validationbuilder</name>
			<arguments>
			</arguments>
		</buildCommand>
		<buildCommand>
			<name>org.maven.ide.eclipse.maven2Builder</name>
			<arguments>
			</arguments>
		</buildCommand>
	</buildSpec>
	<natures>
		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
		<nature>org.eclipse.jdt.core.javanature</nature>
		<nature>org.maven.ide.eclipse.maven2Nature</nature>
		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
	</natures>
</projectDescription>

pom.xml

<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>uk.co.v-s-f</groupId>
	<artifactId>MyApp</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>MyApp</name>
	<properties>
		<version.spring>3.0.5.RELEASE</version.spring>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.5.0</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.5.4</version>
		</dependency>
		<dependency>
			<groupId>net.sourceforge.jtds</groupId>
			<artifactId>jtds</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.13</version>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.8.2</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>3.3.1.GA</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-annotations</artifactId>
			<version>3.4.0.GA</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.13</version>
		</dependency>

		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.9.0.GA</version>
		</dependency>

	</dependencies>
</project>

org.eclipse.wst.common.component

<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
    <wb-module deploy-name="MyApp">
        <wb-resource deploy-path="/" source-path="/WebContent"/>
        <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
        <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
        <property name="context-root" value="MyApp"/>
        <property name="java-output-path" value="/MyApp/target/classes"/>
    </wb-module>
</project-modules>

So once that’s all been put in the relevant directories, it should look something like this:
Spring MVC 3.0, Hibernate and Maven

I’m going to be adding ExtJS to this soon, so check back in a month or two to see ExtJS integration.

Sorry, the comment form is closed at this time.