`
chenying998179
  • 浏览: 25148 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring 3.0 MVC + Hibernate : Simplified with Annotations – Tutorial

    博客分类:
  • java
 
阅读更多

Spring has an awesome feature to deal with Hibernate. For a traditional Hibernate application, you need a hibernate configuration file, a number of mapping files for tables. But Spring reduces that overhead and introduces a new Annotation based mapping. At last, we dont need to brag with that XML files and much cleaner when it looks in POJO.

Thanks Patrick Grimard for giving such wonderful article. I just altered his code according to my need and the tutorial was written by him.

Lets have a look at this. First we need to map the DispatcherServlet in the web.xml file.

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

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

The next thing to configure will be your minimal web application context for Spring.
The spring config file is


<?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:context="http://www.springframework.org/schema/context"
    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/context


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


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

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

    <context:property-placeholder location="classpath:jdbc.properties" />
    <context:component-scan base-package="com.springmvc" />
    <tx:annotation-driven />
    <bean id="jspViewResolver">
        <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="dataSource">
        <property name="driverClassName" value="${database.driver}" />
        <property name="url" value="${database.url}" />
        <property name="username" value="${database.user}" />
        <property name="password" value="${database.password}" />
    </bean>

    <bean id="sessionFactory">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.springmvc.model.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.connection.pool_size">${hibernate.connection.pool_size}</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
</beans>

With Spring having introduced schema based configuration in Spring 2.0, it greatly reduces the amount of XML verbosity in your configuration file, hence this minimal web application context.

The context:property-placeholder element which we use to tell the Spring container where to find some properties files for resolving ${} type placeholders within our application context.

The context:component-scan element that tells Spring where to begin scanning our package for annotated components like @Repository, @Service, @Controller, etc.  Using this element also automatically implies the context:annotation-config element’s behavior to scan for things like @Autowired and several other annotations.  Therefore you don’t need both elements in your application context.

The tx namespace is responsible for handling our database transactions.  Using the tx:annotation-driven element, we’re telling Spring to look for beans annotated with @Transactional and handle them according to the parameters defined in those annotations.  You’ll also notice on line 58, we’ve defined a TransactionManager implementation bean that gets automatically wired into our annotated configuration for handling the transactions.  Because we named our TransactionManager simply “transactionManager” in our configuration, it automatically gets wired into our annotated configuration, this is the Spring default.  If we had given it a different name, we would have had to add the transaction-manager attribute to the tx:annotation-driven element and specify the id of our TransactionManager implementation bean.

Our TransactionManager defines one property named sessionFactory, which references our sessionFactory bean. Our sessionFactory bean is required for Hibernate and more importantly, being an AnnotationSessionFactoryBean, it will allow us to annotate domain objects at the code level, rather than define our mappings to the database tables in separate mapping XML files.  We define Hibernate specific properties within our configuration file, rather than in a hibernate configuration XML file.

The parameters within the ${} place-holders can be accessed from a properties file. Just make sure that you dropped your properties file somewhere in the classpath.
One of the main reasons for using Hibernate is to persist domain objects to a datasource without the need for writing ugly SQL statements, acquiring connections and cleaning up those connections, etc.  Hibernate does this for you.

A Simple class definition for User entity

package com.springmvc.model;

import java.util.Date;

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

@Entity
@Table(name = "USER")
public class User {

	@Id @GeneratedValue
	@Column(name = "USER_ID" )
	private Long id;

	@Column(name = "USERNAME")
	private String username;

	@Column(name = "PASSWORD")
	private String password;

	public User() {}

	public Long getId() {
		return id;
	}

	private void setId ( Long id ) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername ( String username ) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword ( String password ) {
		this.password = password;
	}

}

Integrating Hibernate with Spring, the standard JPA annotations work just as well and that’s what I’m using here.

First we’ve annotated the class with @Entity which tells Hibernate that this class represents an object that we can persist.

The @Table(name = “USER”) annotation tells Hibernate which table to map properties in this class to.

The first property in this class is our object ID which will be unique for all events persisted.  This is why we’ve annotated it with @Id.  The @GeneratedValue annotation says that this value will be determined by the datasource, not by the code.  Lastly the @Column(name = “USER_ID”) annotation is used to map this property to the USER_ID column in the USER table.  The other two properties are annotated in the same fashion, but merely with the @Column attribute.

Here is our simple Controller implementation for a Controller which handles User registration and viewing it back.

package com.springmvc.controller;

import java.util.HashMap;
import java.util.Map;

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.servlet.ModelAndView;

import com.springmvc.model.User;
import com.springmvc.service.UserService;

@Controller
@RequestMapping("/users")
public class UserController {

	@Autowired
	private UserService userService;

	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public ModelAndView addUser ( @ModelAttribute("user") Event event) {
		return new ModelAndView ( "userAdd" );
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView viewUsers() {
		Map model = new HashMap();
		model.put ( "users", userService.getAllUsers() );

		return new ModelAndView ( "userView", model );
	}

}

I’ve annotated the UserController class with @Controller and @RequestMapping(“/users”) on line 18 and 19.  When Spring scans our package, it will recognize this bean as being a Controller bean for processing requests.  The @RequestMapping annotation tells Spring that this Controller should process all requests beginning with /users in the URL path.  That includes /users/* and /users.html.

An UserService bean will be autowired and injected by Spring since we applied the @Autowired annotation to the private property. The property name is important because Spring will look for a bean named userService to inject.

The first method named addUser is annotated with @RequestMapping(value = “/add”, method = RequestMethod.GET).  The annotation tells Spring that requests to /users/save.html should be processed by this method, but only if the request method is GET.  The method signature annotates one of the parameters with @ModelAttribute(“users”) which has to do with our JSP page. The important part of this method is the userService.addUser ( user ).  This is a call to our service bean to add our domain object to the datasource when it’s entered in the browser.  It returns a ModelAndView object to resolve the view by logical name. Lets say it redirect to /users.html, which will also be handled by this Controller.

The next method viewUsers is basically our default method when a simple GET request is made to /users.html, you can see this by the annotation @RequestMapping(method = RequestMethod.GET) .  This method creates a Map and adds the data to the map by invoking the userService.getAllUsers() method.  That call returns a List object.  The method returns another ModelAndView object, but this time it will try to resolve to a view named userView and the data model is being passed back to the browser so we can access the data within the JSP. The logical view name will resolve to “/WEB-INF/jsp/userView.jsp” when processed by the jspViewResolver configured in the application context.

Next main thing is, having the Business layer. Here comes our ServiceImpl

package com.springmvc.service;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.springmvc.dao.EventDao;
import com.springmvc.model.User;

@Service("userService")
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;

	public UserServiceImpl() {}

	@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
	public void addUser(User user) {
		userDao.saveUser ( user );
	}

	public List<Event> getAllUsers() {
		return usertDao.getAllUsers();
	}

}

This service bean implements the UserService interface which provides our contract of what this implementation will do.

The class is annotated with @Service(“userService”).  This is the meta data that Spring will use when autowiring the userService property in the Controller created in the previous step.  We’ve explicitly defined the name “userSerivice” in the annotation’s value, otherwise without it Spring would have named the bean “userServiceImpl” automatically and the autowiring of this bean in the Controller and other classes would have failed.

The @Transactional(propagation=Propagation.SUPPORTS, readOnly=true) annotation will be recognized by the tx:annotation-driven element in the application context.  Having placed the annotation at the class level means that all methods in this class by default should adhere to these transaction rules.  propagation=Propagation.SUPPORTS means a transaction isn’t necessary, but if one exists, then the method will run in that transaction.  The readOnly=true attribute is pretty straight forward, by default all data retrieved should be read only.  No writes to the datasource are permitted.

An EventDao object gets autowired.  That class will deal with the actual ORM framework, in this case, Hibernate.Another @Transactional annotation has been applied at the method level. This time @Transactional(propagation=Propagation.REQUIRED, readOnly=false) tells the transaction manager that this method requires a transaction.  This is defined by the propagation=Propagation.REQUIRED attribute.  The readOnly=false attribute overrides the class level readOnly=true so that we are permitted to write to the datasource.  That’s an important thing to keep in mind.  When you annotate at the class level, the rules are applied to every method, but if you need to override the class level attributes, you can do so by annotating the methods in question, overriding whatever attributes you need to.  In this case, since the method will write to the datasource, we require a transaction and write permissions.

below is our HibernateDAO Implementation

package com.springmvc.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.springmvc.dao.User;

@Repository("userDao")
public class HibernateEventDao implements EventDao {

	@Autowired
	private SessionFactory sessionFactory;

	public void saveEvent ( Event event ) {
		sessionFactory.getCurrentSession().saveOrUpdate ( event );
	}

	@SuppressWarnings("unchecked")
	public List<Event> getAllEvents() {
		return (List<Event>) sessionFactory.getCurrentSession().createCriteria ( Event.class ).list();
	}

}

asasasa

The @Repository(“userDao”) meta data tells Spring this class is a DAO object and Spring should name it “userDao” so that it can be properly autowired into the userService bean from the previous step.The Hibernate SessionFactory will be autowired by Spring.  If you remember, the SessionFactory was defined in the application context with the bean id “sessionFactory” and thus Spring will autowire into this property since it has the same name with the @Autowired annotation.The saveUser method is defined.  It interacts with the session factory by getting the current Hibernate Session and calling the saveOrUpdate method, passing in the User object that was passed to the method.  If the User object has an existing USERID, Hibernate will attempt to update that record in the datasource, if it’s not found, it will try to insert it.The listUserdefines the DAO method for retrieving existing Events from the datasource.  It only contains 1 simple line.  First the current Session is retrieved from the SessionFactory, and then a Criteria is created from that Session, into which we simply pass the User.class common name, followed by a call to list().  So what we’ve done is essentially told Hibernate, select all records from the table that User.class is mapped to, and return all property values of the User class in the form of a java.util.List object.

The next part is view. Here we create a file userView.jsp to display all the available users.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>

<!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>
<link rel="stylesheet" type="text/css" href="css/styles.css"></link>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Existing Events</title>

</head>

<body>
<h1>Existing Users</h1>

<br /><br />
<c:if test="${!empty user}">
	<table>
		<tr>
			<th>ID</th>
			<th>Title</th>
			<th>Date</th>
		</tr>

		<c:forEach items="${users}" var="user">
		<tr>
			<td><c:out value="${user.username}" /></td>
			<td><c:out value="${user.password}" /></td>
		</tr>
		</c:forEach>
	</table>
</c:if>
<c:if test="${empty username}">
  No username found in the Database
</c:if>
</body>
</html>

Next thing would be creating userAdd.jsp page to add a new user

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

<!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=UTF-8" />
<title>Add Event</title>

</head>

<body>
<h1>Add User</h1>
<c:url var="viewUsersUrl" value="/users.html" />
<a href="${viewUsersUrl}">View All Users</a>

<br /><br />
<c:url var="addUserUrl" value="/users/save.html" />
<form:form modelAttribute="user" method="POST" action="${addUserUrl}">
	<form:label path="username">Username:</form:label>
	<form:input path="username"/><br />
	<form:label path="password">Password:</form:label>
	<form:input path="password"/><br />
	<input type="submit" value="Save User" />
</form:form>

</body>
</html>

No need to define these JSP pages assuming that you’ve a basic knowledge of JSTL.The only important thing to note here was the mapping names. Note that the Mapping we made using Annotations at Controller must match in the JSP pages. Otherwise it’ll not retrieve or do any process. This is a simple Hibernate-Spring Integration project by me. I hadn’t used any ORM’s before and with Hibernate, i am sure that i’m pretty much impressed. Atleast i get rid of those annoying long SQL sentences.

I’d prefer NetBeans over Eclipse as it comes bundled with Spring and Hibernate Framework Support, which means saving a lot of time. It’ll create you the POJO mapping files and everything easily. The Spring 3.0 Module for NetBeans is available for download.

Source : http://jpgmr.wordpress.com/2009/12/08/spring-mvc-and-hibernate-made-simple-with-annotations/

I’ve downloaded the code from the above link and used it as the base for my project.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics