Sử dụng Framework Hibernate trong Java Web Application
Bài đăng này đã không được cập nhật trong 3 năm
Hibernate Framework
Framework trong phần mềm là một khái niệm dùng để chỉ những “cấu trúc dùng để hỗ trợ đã được định nghĩa sẵn” mà trong đó những dự án phần mềm khác có thể sử dung nó để phát triển. Một framework bao gồm những program hỗ trợ, core library và một ngôn ngữ lập trình để giúp phát triển và gắn những thành phần khác nhau ứng dụng phần mềm lại với nhau. Hibernate là một trong những ORM Framework. Hibernate framework là một framework cho persistence layer. Như vậy sử dụng Hibernate framework giúp bạn phát triển ứng dụng nhanh và chỉ còn chú tâm vào những layer khác mà không cần chú tâm nhiều đến persistence layer nữa. Hibernate giúp lưu trữ và truy vấn dữ liệu quan hệ mạnh mẽ và nhanh. Hibernate cho phép bạn truy vẫn dữ liệu bằng ngôn ngữ SQL mở rộng của Hibernate (HQL) hoặc bằng SQL thuần.
Trong bài viết này tôi sẽ hướng dẫn các bạn làm quen với framework Hibernate qua những thao tác đơn giản. Hibernate cung cấp công cụ object relational mapping ORM như đã nói ở trên nên trong bài viết này tôi sẽ sử dụng luôn thế mạnh của framework này kết hợp cùng "JSF managed bean" và "JSF 2.x pages" để hiển lấy về dữ liệu và hiển thị ra giao diện web application.
Công cụ và môi trường phát triển
Trong bài viết này tôi sử dụng môi trường window 8.1 và cài đặt những IDE hỗ trợ sau:
- Java SE Development Kit 8u71
- Netbean IDE 8.1
- XamPP 5.6.15 - For Mysql Version 5.x
- GlassFish Server 4.1.1 - Nên chọn Netbean có sẵn server này (hoặc có thể dùng Jboss, Apache Tomcat...)
Các bạn có thể dùng các hệ quản trị cơ sử dữ liệu khác như Oracle DB, Sql Server ... IDE để soạn thảo code thì có thể dùng những lựa chọn khác như eclip, IntelliJ IDEA ... mỗi editor tool đều có sự khác biệt một chút nhưng đa phần đều support Hibernate.
Tạo mới một database
Trong bài viết này tối sẽ sử dụng luôn IDE netbean để tạo mới và thao tác với database. Để tạo một database các vào tab Services
click chuột phải vào connection và chọn Create Datatbase...
ở đây tôi lấy tên database là liem_report_db
các bạn có thể thay đổi tùy theo ý thích
Bây giờ chúng ta sẽ tạo ra một table có với tên là User
ở đây là table demo nên tôi chỉ tạo ít field, các bạn có thể tùy biến để phù hợp với yêu cầu công việc
như vậy là chúng ta đã có table User
nhưng chưa có dữ liệu nên chúng ta sẽ thêm môt ít dữ liệu demo. Để thực hiện câu lệnh query luôn trên IDE thì chúng ta click chuột phải vào connect và chọn Execute Command...
Test dữ liệu vừa thêm vào
Select * from User;
Và chúng ta có kết quả:
Lưu ý: những bước ở trên mục đích là để tạo một database và thiết lập dữ liệu trong đó để sử dụng sau này, nếu bạn đã có database rồi thì không cần phải thực hiện loại. Tên database, tables, fields có thể tùy biến theo ý thích.
Tạo mới một project Web Application
Để tạo mới một project trong Netbean khá dễ bạn chỉ cần thao tác theo những bước sau:
- Trên thanh Menu bạn chọn
File
>New Project
(sử dung phím tắt Ctrl-Shift-N). Ở phầnCategory
bạn chọn loại ứng dụng muốn tạo làWeb Application
sau đó click vào nútNext
.
Ở bước này tôi sẽ yêu cầu chọn Server
để Run
project ở đây tôi chọn luôn server Glass Server 4.1.1
đi kèm sẵn trong bản Netbean. Các bạn có thể chọn server khác.
Đến bước này khá quan trọng, các bạn chọn JavaServer Faces
và Hibernate 4.3.1
có thể version sẽ khác đi, tùy thuộc vào version của bản framework bạn bạn tích hợp vào Netbean
Sau đó click vào button Finish
. Thế là chúng ta đã tạo ra một project được import các library của Hibernate và JSF (JavaServer Faces)
Hệ thống sẽ tự động sinh ra cho chúng ta một file có tên hibernate.cfg.xml
nằm trong Source Packages
> <default package>
giờ chúng ta sẽ thêm một số config cho nó như sau:
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/liem_report_db</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"/>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
nếu các bạn để ý thì đây là những property
cung cấp thông tin connection, việc này sẽ giúp cho Hibernate có thể thao tác với database của chúng ta.
Thẻ cuối cùng hơi đặc biệt một chút
<property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
ở đây chúng ta khai báo class sẽ xử lý genarate ra câu lệnh sql. Trong bản Hibernate 4 tôi sử dụng đường dẫn package như vây, nếu bạn sử dụng bản khác (thấp hơn) thì thay đổi đường dẫn tương ứng
Tạo mới một class HibernateUtil.java
Để tạo mới một Hibernate Util class chúng ta thao tác như sau:
- Chuột phải vào
Source Packages
chọnNew
>Other
để mở cửa sổNew File wizard
. - Chọn
Hibernate
từ list danh mục và ở khung đối diệnFile Types
ta chọnHibernateUtil.java
. Sau đó click vào buttonNext
. Type HibernateUtil for the class name and dvdrental for the package. Click Finish.
Nhập vào tên cho class bạn muốn tạo. Ở đây tôi đặt tên là HibernateUtil
cho dễ nhớ và chọn Package
là app
bạn có thể tùy biến tên class và package.
Tiếp theo chúng ta sẽ tạo một file Hibernate Reverse Engineering
mục đích là để phục vụ cho việc mapping dữ liệu
Sau đó click vào button Next
và chúng ta thấy hiện ra table có tên user
như hình dưới:
Đây chính là tên table tôi tạo lúc đầu trong database, nếu các bạn tạo table khác thì tên nó sẽ hiện ra trong đó. Chúng ta chọn table và nhấn vào button Add
move sang khung Selected Table
sau đó chúng ta click button Finish
Hibernate Mapping Files and POJOs
Bây giờ chúng ta sẽ sử dụng Hibernate Mapping Files and POJOs để generate file từ table user
đã chọn ở trước đó. Chúng ta thực hiện như sau:
- Chuột phải vào
Source Packages
chọnNew
>Other
để mởNew File wizard
. - Sau đó chúng ta chọn
Hibernate
ở khung bên cạnh chọnHibernate Mapping Files and POJOs from Database
sau đó click vào buttonNext
. - Trong dropdown list chọn file cấu hình
hibernate.cfg.xml
vàhibernate.reveng.xml
- Check vào
JDK 5 Language Features
- Check vào
Domain Code
vàHibernate XML Mappings
để hệ thống nhận biết định dạng cần thiết để generate code. - Đặt tên cho
Package name
tôi chọn làapp
. Sau đó click vào buttonFinish
.
Ở công đoạn này nhiều người thường hay gặp phải message thông báo lỗi như hình dưới:
Nguyên nhân là do hệ thống không tìm được class ClassicQueryTranslatorFactory
mà bạn đã cung cấp ở file cấu hình của Hibernate. Hãy kiểm tra lại version của hibernate và chỉnh sửa lại package cho đúng ở thuộc tính
<property name="hibernate.query.factory_class">org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</property>
Lưu ý: để nhanh chóng check xem đường dẫn đã đúng hay chưa bạn chỉ cần tạo mới một Class và import đường dẫn đó vào, nếu không tồn tại IDE sẽ báo đỏ, còn không thì đường dẫn là hợp lệ
Sau đó ta click vào Finish
. Hệ thống sẽ tự động sinh ra 2 file mới trong app package đó là User.java
và User.hbm.xml
Class User đã có sẵn các field và được mapping thành các property dễ dàng cho việc thao tác sau này. User.hbm.xml
chứa thông tin mapping với user table:
File: User.java
import java.util.Date;
/**
* User generated by hbm2java
*/
public class User implements java.io.Serializable {
private int id;
private String firstName;
private String lastName;
private String username;
private String password;
private Date created;
public User() {
}
public User(int id, String username) {
this.id = id;
this.username = username;
}
public User(int id, String firstName, String lastName, String username, String password, Date created) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
this.password = password;
this.created = created;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreated() {
return this.created;
}
public void setCreated(Date created) {
this.created = created;
}
}
File: User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Jan 27, 2016 9:46:18 AM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="app.User" table="user" catalog="liem_report_db" optimistic-lock="version">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="firstName" type="string">
<column name="first_name" length="50" />
</property>
<property name="lastName" type="string">
<column name="last_name" length="50" />
</property>
<property name="username" type="string">
<column name="username" length="20" not-null="true" unique="true" />
</property>
<property name="password" type="string">
<column name="password" length="32" />
</property>
<property name="created" type="time">
<column name="created" length="8" />
</property>
</class>
</hibernate-mapping>
Test query với HQL Query
Hibernate hỗ trợ thực thi HQL query để phục vụ cho việc truy xuất dữ liệu trong quá trình phát triển, bước này để test xem việc config, dữ liệu để connect tới db, mapping data đã thành công hay chưa:
Chuột phải vào file hibernate.cfg.xml
chọn Run HQL Query
để mở cửa sổ HQL Query
sau đó ta thực hiện câu lệnh truy vấn
from User
Và được kết quả như trong ảnh, nếu không hiện ra hoặc báo Generate erro
thì bạn kiểm tra lại file cấu hình của hibernate
Tạo mới class UserHelper.java
Chúng ta tạo chuột phải vào app
package để create một class tên có thể tùy biến, ở đây tôi đặt là UserHelper
cho dễ nhớ:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package app;
/**
*
* @author DUYLIEMPRO
*/
public class UserHelper {
public UserHelper() {
}
}
Sau đó viết thêm các method để lấy dữ liệu ra:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package app;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
/**
*
* @author DUYLIEMPRO
*/
public class UserHelper {
Session session = null;
List<User> userList;
public UserHelper() {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
@SuppressWarnings("unchecked")
public List<User> getUserList() {
userList = new ArrayList<User>();
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery("from User as user");
userList = (List<User>) q.list();
} catch (Exception e) {
userList = null;
e.printStackTrace();
}
return userList;
}
public User getUserByID(int userId) {
User user = null;
try {
org.hibernate.Transaction tx = session.beginTransaction();
Query q = session.createQuery("from User as user where user.id=" + userId);
user = (User) q.uniqueResult();
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
}
Tạo mới JSF Managed Bean
Bước này mục đích là tạo ra bean class để lấy dữ liệu fill ra file view. Để tạo một bean class các bạn thực hiện như sau:
- Chuột phải vào
source package
chọnNew
>Other
. - Chọn
JSF Managed Bean
trong danh mụcJavaServer Faces
. Sau đó clickNext
. - Nhập tên bean class
UserController
. - Nhập tên package là
app
- Nhập
UserController
cho ôname
sau này sẽ được sử dụng gọi ở file view (managed bean) 6 Thiết lậpScope
làSession
. Sau đó click vàoFinish
.
File: UserController.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package app;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
/**
*
* @author DUYLIEMPRO
*/
@Named(value = "userController")
@SessionScoped
public class UserController implements Serializable {
/**
* Creates a new instance of UserController
*/
public UserController() {
}
}
Chúng ta sẽ viết các method xử lý lấy dữ liệu vào class này, ở đây tôi sẽ viết ví dụ 2 method, các bạn có thể thêm tùy ý:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package app;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import java.io.Serializable;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
/**
*
* @author DUYLIEMPRO
*/
@Named(value = "userController")
@SessionScoped
public class UserController implements Serializable {
DataModel useList;
UserHelper helper;
private User current;
/**
* Creates a new instance of UserController
*/
public UserController() {
helper = new UserHelper();
}
public User getSelected() {
if (current == null) {
current = new User();
}
return current;
}
public DataModel getUseList() {
if (useList == null) {
useList = new ListDataModel(helper.getUserList());
}
return useList;
}
}
Lưu ý
Muốn sử dụng được những function này trong file view (.xhtml) thì bắt buộc chúng ta phải viết tên method theo quy ước "get" + tên method(Tên method phải viết hoa chữ cái đầu). Khi hiển thị trên file view thì tiền tố "get" tự động sẽ bị remove, chữ cái đầu trong tên method sẽ tự động chuyển sang thường.
Tạo mới file Web Pages
Ở đây tôi sẽ sử dụng template để dễ dàng hơn cho việc thiết lập layout chung cho nhiều page, để tạo một template các bạn làm như sau:
- Chuột phải vào
source package
chọnNew
>Other
. - Chọn
Facelets Template
trong danh mụcJavaServer Faces
. sau đó clickNext
. - Tôi đặt tên là
template
và chọn layout style sử dụngCSS
(Table đều được). - Click vào button
Finish
. Kết quả là chúng ta được một file: template.xhtml trong thư mục web pages
<?xml version='1.0' encoding='UTF-8' ?>
<!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"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<h:outputStylesheet name="./css/default.css"/>
<h:outputStylesheet name="./css/cssLayout.css"/>
<title>Facelets Template</title>
</h:head>
<h:body>
<div id="top" class="top">
<ui:insert name="top">Top</ui:insert>
</div>
<div id="content" class="center_content">
<ui:insert name="content">Content</ui:insert>
</div>
</h:body>
</html>
Tùy layout bạn chọn mà sẽ có nội dung khác nhau nhưng tất cả đều thẻ
<ui:insert name="content">Content</ui:insert>
Đây là nơi mà nội dung sẽ được chèn vào khi sử dụng template này.
Khi tạo mới ứng dụng hệ thống sẽ tự động tạo mới cho ta file index.xhtml
trong thư mục Web Pages
chúng ta sẽ sử dụng luôn file này để hiển thị dữ liệu. Tôi sẽ sử dụng JSF lib để sử dụng layout và hiển thị dữ liệu ra:
<?xml version='1.0' encoding='UTF-8' ?>
<!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"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:composition template="./template.xhtml">
<ui:define name="content">
<h:form>
<h:dataTable value="#{userController.useList}" var="item" border="0" cellpadding="2" cellspacing="0" rowClasses="jsfcrud_odd_row,jsfcrud_even_row" rules="all" style="border:solid 1px">
<h:column>
<f:facet name="header">
<h:outputText value="id"/>
</f:facet>
<h:outputText value="#{item.id}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="first_name"/>
</f:facet>
<h:outputText value="#{item.first_name}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="last_name"/>
</f:facet>
<h:outputText value="#{item.last_name}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="username"/>
</f:facet>
<h:outputText value="#{item.username}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="password"/>
</f:facet>
<h:outputText value="#{item.password}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="created"/>
</f:facet>
<h:outputText value="#{item.created}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value=" "/>
</f:facet>
</h:column>
</h:dataTable>
<br/>
</h:form>
</ui:define>
</ui:composition>
</html>
Lưu ý
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
Đây là khai báo tên các thẻ sẽ được sẽ được sử dụng trong file view . Các bạn có thể thay đổi tên thẻ sẽ sử dụng vd: xmlns:a="http://java.sun.com/jsf/html" và lúc dùng gọi <a:form>
Run Project
- Để chạy thử project các bạn chuột phải vào tên project chọn
Clean and Build
để hệ thống compile nếu có lỗi sẽ thông báo ở cửa sổ Output dưới. 2. Sau khi build xong chúng ta chuột phải vào projec một lần nữa chọn run (Lần đầu hệ thống sẽ startGlassFish Server
nên hơi lâu một chút) nếu ok dưới cửa sổ sẽ thông báo
Incrementally deploying report
Completed incremental distribution of report
run-deploy:
Browsing: http://localhost:8080/report
run-display-browser:
run:
BUILD SUCCESSFUL (total time: 0 seconds)
và trình duyệt sẽ bật ra cửa sổ vối đường link: http://localhost:8080/report
Và chúng ta được kết quả như hình bên dưới:
Database file
Đây là file datbase export cho những bạn nào cần:
CREATE DATABASE `liem_report_db`;
USE `liem_report_db`;
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`first_name` varchar(50) DEFAULT NULL,
`last_name` varchar(50) DEFAULT NULL,
`username` varchar(20) NOT NULL,
`password` varchar(32) DEFAULT NULL,
`created` time DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `user` VALUES ('1', 'Tran', 'Liem', 'tranducliem', '25f9e794323b453885f5181f1b624d0b', '00:00:00');
INSERT INTO `user` VALUES ('2', 'Le', 'Minh', 'levanminh', '25f9e794323b453885f5181f1b624d0b', '00:00:00');
INSERT INTO `user` VALUES ('3', 'Phan', 'Tuan', 'phanquoctuan', '25f9e794323b453885f5181f1b624d0b', '00:00:00');
INSERT INTO `user` VALUES ('4', 'Tran', 'Sang', 'tranvansang', '25f9e794323b453885f5181f1b624d0b', '00:00:00');
Bài viết có tham khảo tài liệu User Guide của [Hibernate Framework](http://hibernate.org/orm/documentation/4.2/).
Xin cảm ơn các bạn rất nhiều ! LiemTD - Framgia.
All rights reserved