Reputation: 741
Status:
Thankful to the answers but No one has answered the Important tag description in reflection to my simple code given. (20 Jul 13)
I have read many tutorials and yet every thing just mixes up or is only as a specific example that looks tiny or abstract.
I really cannot make something get logical in my mind. May be I learn with specific actual code.
Question: Can anyone show how to make the following incomplete code work completely
with spring 3.x and hibernate 4.x.
Important:
I would like, even in this simple example, make sessionfactory and database quering by hibernate in the Service class (making boundry there as in large applications Service classes use many DAOs and commit transactions in one go)
I forget where i read it, perhaps in the spring documentation - but it clearly said, don't put @Transactional on your DAOs :P so generally, your service tier is where you define your transaction boundaries. a service method is typically a chunk of things that if all pass, commit otherwise fail and rollback That may not be a diehard rule of course, but its how we architected our enterprise resource planning web core. I forget where i read it, perhaps in the spring documentation - but it clearly said, don't put @Transactional on your DAOs
e.g http://blog.patouchas.net/technology/hibernate-dao-java-tutorial/ like without spring ?
The annotations are missing or incorrect. What should be the correct annotations.
Would there be any spring.xml (other than the usual) for these classes in specific? I would like to prefer only annotations if it works. correct annotations like @component , service, repository, resource, autowired
This is how I get the transaction generally
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.getTransaction().commit();
session.close();
now spring and hibernate
@Controller
public class UserController {
private IUserService userService;
@RequestMapping("/users")
public String creatUser(){
Users user = new Users();
user.setEmail("[email protected]");
user.setName("myname");
userService.creatUser(user);
return "user-creation-result";
}
}
public class UserService implements IUserService{
private IUserDAO userDAO;
public void creatUser(Users user){
//what to do here
//how to call the sessionfactory
//and call it in a way that each call
// gives the same instance
userDAO.creatUser(user);
}
}
public class UserDAO implements IUserDAO{
public void creatUser(Users user){
// what to do here?
}
}
this wont be so important though.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5432/postgres</property>
<property name="connection.username">postgres</property>
<property name="connection.password">abc</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<!-- Names the annotated entity class -->
<mapping class="taskmanagsetup.Boards" />
<mapping class="taskmanagsetup.BoardPrivileges" />
<mapping class="taskmanagsetup.Boxes" />
<mapping class="taskmanagsetup.BoxPrivileges" />
<mapping class="taskmanagsetup.Groups" />
<mapping class="taskmanagsetup.Tasks" />
<mapping class="taskmanagsetup.TaskPrivileges" />
<mapping class="taskmanagsetup.Users" />
</session-factory>
</hibernate-configuration>
@Entity
public class Users {
@Id
@GeneratedValue
private long id;
@ManyToMany
private Collection<Groups> groupList = new ArrayList<Groups>();
private String type; // admin / teamlead / normal
private String name;
private String email;
private String password;
@Lob
private String description;
private boolean isEnabled;
/**
* @return the id
*/
public long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(long id) {
this.id = id;
}
/**
* @return the groupdId
*/
/**
* @param groupdId the groupdId to set
*/
/**
* @return the type
*/
public String getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(String type) {
this.type = type;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the email
*/
public String getEmail() {
return email;
}
/**
* @param email the email to set
*/
public void setEmail(String email) {
this.email = email;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the isEnabled
*/
public boolean isIsEnabled() {
return isEnabled;
}
/**
* @param isEnabled the isEnabled to set
*/
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}
/**
* @return the groupList
*/
public Collection<Groups> getGroupList() {
return groupList;
}
/**
* @param groupList the groupList to set
*/
public void setGroupList(Collection<Groups> groupList) {
this.groupList = groupList;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
}
Upvotes: 1
Views: 11375
Reputation: 42020
If you are using Spring 3.x and Hibernate 4.x, you can consider a three-tier application architecture:
You could have an abstract base class for common DAO methods.
public abstract class AbstractDAO<E extends Serializable,
PK extends Serializable> {
private final transient Class<E> entityClass;
public AbstractDAO(final Class<E> entityClass) {
this.entityClass = entityClass;
}
protected abstract EntityManager getEntityManager();
public final E find(final PK id) {
return getEntityManager().find(entityClass, id);
}
// Another common methods
}
In every DAO implementation, you can put particular methods for that DAO.
@Repository
public final class UserDAO extends AbstractDAO<User, Long> {
@Autowired
private transient EntityManagerFactory emf;
public UserDAO() {
super(User.class);
}
@Override
protected EntityManager getEntityManager() {
return emf.createEntityManager();
}
// particular methods for this DAO
}
What if the user does not exist? Put this logic in this tier.
@Service
public final class UserService {
private static final Logger LOG = LoggerFactory.getLogger(UserService.class);
@Autowired
private transient UserDAO userDAO;
public User findUser(final Long id) {
return userDAO.find(id);
}
}
@Controller
@RequestMapping("/user")
public final class UserController {
private static final Logger LOG = LoggerFactory
.getLogger(UserController.class);
@Autowired
private transient UserService userService;
@RequestMapping(value = "/find/{id}", method = RequestMethod.GET)
public void downloadImage(
@PathVariable("id") final Long id,
final HttpServletResponse response) throws IOException {
//
}
}
The web.xml
, this contains the Application config and the Dispatcher config:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>MyWebApp</display-name>
<!-- log4j -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>MyWebApp.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!-- Spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Welcome -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
The dispatcher-servlet.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans ···>
<context:component-scan base-package="···.mywebapp" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven />
</beans>
And if you want to avoid the persistence.xml
file, you can have it in your applicationContext.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans ···>
<bean id="dataSource" class="···">
<property name="URL" value="···" />
<property name="user" value="···" />
<property name="password" value="···" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource" p:packagesToScan="···.model">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:showSql="false" p:databasePlatform="org.hibernate.dialect.SQLServerDialect" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<context:component-scan base-package="···.mywebapp" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Repository" type="annotation"/>
<context:include-filter expression="org.springframework.stereotype.Service" type="annotation"/>
</context:component-scan>
</beans>
I hope this can help you.
Upvotes: 7
Reputation: 1102
i dont know the best practice but this code worked for me :
i write HibernateUtil to connect to DB :
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
System.out.println("session Factory = "+sessionFactory.toString()+" current session="+sessionFactory.getCurrentSession()+
" collection="+sessionFactory.getAllCollectionMetadata()+" collection="+sessionFactory.getStatistics());
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
one of my model :
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class Product {
@ManyToOne
@JoinColumn(name = "providerid")
private Provider provider;
@Id
private String productCode;
private int nominal;
private double buyPrice;
private double sellPrice;
@ManyToOne
@JoinColumn(name = "supplierid")
private Supplier supplier;
public Product(){
}
public Product(String id){
setProductCode(id);
}
//setter and getter
}
DAO :
import java.util.List;
public interface ProductDAO {
public void save(Product product, int mode);
public List<Product> list();
public Product get(String id);
}
DAO Implementation :
import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import com.util.HibernateUtil;
import com.util.SessionHelper;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class ProductDAOImpl implements ProductDAO {
private HibernateTemplate hibernateTemplate;
private TableIDDAO tableIDDao;
public void setTableIDDao(TableIDDAO tableIDDao) {
this.tableIDDao = tableIDDao;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
@Override
public void save(Product product, int mode) {
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = sf.getCurrentSession();
Transaction tr = session.beginTransaction();
session.saveOrUpdate(product);
tr.commit();
}
@Override
@SuppressWarnings("unchecked")
public List<Product> list() {
return hibernateTemplate.find(" from Product ");
}
@Override
public Product get(String id) {
List<Product> list = hibernateTemplate.find(" from Product where productCode='" + id + "'");
Product c = null;
if (!list.isEmpty()) {
c = list.get(0);
}
return c;
}
}
Controller (from controller we call dao - i write this long time ago so still use modelandview, its better if you use annotation cause modelandview is obsolete) :
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.util.SessionHelper;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
public class ProductController extends MultiActionController {
private ProductDAO productDAO;
public void setProductDAO(ProductDAO productDAO) {
this.productDAO = productDAO;
}
public ProductController() {
System.out.println("Masuk ke Contrutctor Product Controller");
}
public ModelAndView add(HttpServletRequest request,
HttpServletResponse response, Product product) throws Exception {
productDAO.save(product,mode);
return new ModelAndView("redirect:list.htm");
}
public ModelAndView list(HttpServletRequest request,
HttpServletResponse response,Page p) throws Exception {
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("productList", page.paging(productDAO.list()));
modelMap.addAttribute("product", new Product());
return new ModelAndView("product", modelMap);
}
}
My JSP :
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<html>
<body>
<div class="content">
<c:if test="${fn:length(productList) > 0}">
<table cellpadding="5">
<tr class="even">
<th>Product Code</th>
<th>nominal</th>
<th>buy price</th>
<th>Sell Price</th>
<th>Provider</th>
<th>Supplier</th>
</tr>
<c:forEach items="${productList}" var="product" varStatus="status">
<td>${product.productCode}</td>
<td>${product.nominal}</td>
<td>${product.buyPrice}</td>
<td>${product.sellPrice}</td>
<td>${product.provider.namaProvider}</td>
<td>${product.supplier.name}</td>
</tr>
</c:forEach>
</table>
</c:if>
<p>Data Form</p>
<form:form action="add.htm" commandName="product">
<table>
<tr>
<td>Product Code :</td>
<td><form:input path="productCode" /></td>
</tr>
<tr>
<td>Nominal :</td>
<td><form:input path="nominal" /></td>
</tr>
<tr>
<td>Buy Price :</td>
<td><form:input path="buyPrice" /></td>
</tr>
<tr>
<td>Sell Price :</td>
<td><form:input path="sellPrice" /></td>
</tr>
<tr>
<td>Provider :</td>
<td><form:select path="provider.providerID" modelAttribute="contact" >
<form:options items="${providerList}" itemValue="providerID" itemLabel="namaProvider" />
</form:select>
</td>
</tr>
<tr>
<td>Provider :</td>
<td><form:select path="supplier.supplierID" >
<form:options items="${supplierList}" itemValue="supplierID" itemLabel="name" />
</form:select>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Register"></td>
</tr>
</table>
</form:form>
</div>
</body>
</html>
and you also need to configure your spring configuration and include it in your web.xml all jsp i put in /WEB-INF/pages/... its up to you if you want put it somewhere else
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/pages/" p:suffix=".jsp" />
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
<property name="url" value="jdbc:mysql://localhost:3306/yourdatabase"/>
<property name="username" value="root"/>
<property name="password" value="yourmysqlpassword"/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>com.bean.Product</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean id="myProductDAO" class="com.dao.ProductDAOImpl">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean name="/product/*.htm" class="com.controller.ProductController" >
<property name="productDAO" ref="myProductDAO" />
</bean>
</beans>
also you need create hibernate.cf.xml in your root of your code :
<?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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/yourdatabase</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">yourmysqlpassword</property>
<property name="hibernate.connection.driver_class"> org.hsqldb.jdbcDriver</property>
<property name="current_session_context_class">thread</property>
<property name="connection.pool_size">3</property>
<property name="show_sql">true</property>
<mapping class="com.bean.Product" />
</session-factory>
</hibernate-configuration>
i dont give you exactly the same to my real code, but i think its enough to give you an inspiration.
Upvotes: 2