Hibernate結合JSP使用
前面幾章詳細的介紹了Hibernate的相關知識,這一章介紹Hibernate結合JSP和Servlet的使用,通過這一章的學習,可以加深對Hibernate的理解。
本章使用的開發工具是MyEclipse5.5,服務器是Tomcat6.0,數據庫是MySQL5.1,本章所有例子源代碼見光盤第14章的工程hibernate_jsp。
14.1 搭建Hibernate框架
使用Hibernate進行開發之前,需要先搭建Hibernate框架,Hibernate框架的搭建在前面已經介紹過。新建一個Web工程,工程名為hibernate_jsp。把連接MySQL數據庫的jar包、Hibernate所需的jar包和JSTL標簽庫的jar包拷貝到該工程的WebRoot/WEB-INF/lib目錄下。在MyEclipse中把工程hibernate_jsp發布到Tomcat服務器中。
14.1.1 創建數據庫表
為了使例子簡單易懂,創建數據庫表時,表字段很少。本章的例子只需兩張表,一張部門表和一張員工表。部門表的建表語句如下:
--
CREATE
)
部門表的主鍵設置成自動增長。部門表和員工表是一對多的關系,所以在員工表中,部門表的主鍵作為員工表的外鍵,員工表的主鍵設置成自動增長。員工表的建表語句如下:
--
CREATE
)
14.1.2 編寫數據庫表對應的實體類和映射文件
數據庫表對應的實體類和實體類映射文件可以使用MyEclipse的向導來自動生成,也可以手動編寫。這里使用MyEclipse的向導來自動生成。部門表對應的實體類Dept源代碼如下:
package
public
//
private
private
private
//
public
}
public
this.depno
}
public
this.depno
this.depname
this.emps
}
//這里省略了sett和getter方法
}
Dept類中有3個屬性depno和depname對應數據庫表的字段。Set集合對應的是一對多的多方,這里是員工實體類。Dept類的對應的映射文件和實體類在同一包下,代碼如下:
<?xml
<!DOCTYPE
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
-->
<hibernate-mapping>
</hibernate-mapping>
員工實體類是一對多關系中的多方,在員工表對應的實體類中要聲明一方的對象(這里是Dept類對象),員工表對應的實體類Emp代碼如下:
package
public
//
private
private
private
//
public
}
public
this.empno
}
public
this.empno
this.dept
this.empname
}
//這里省略了setter和getter方法
}
用個實體類中有3個成員變量,empno和empname是數據庫表這段對應的屬性。Dept是員工表外鍵對應的屬性,是一對多關系映射中的一方。Emp類對應的映射文件和實體類在同一包下,代碼如下:
<?xml
<!DOCTYPE
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
-->
<hibernate-mapping>
<!--
</hibernate-mapping>
14.1.3 編寫Hibernate的配置文件
這個例子中使用XML文件來作為Hibernate的配置文件,文件名為hibernate.cfg.xml,在該文件中配置數據庫連接和實體類映射文件,配置文件在src的跟目錄下,代碼如下:
<?xml
<!DOCTYPE
<!--
<hibernate-configuration>
</hibernate-configuration>
14.1.4 編寫 HibernateSessionFactory類
HibernateSessionFactory類是原來初始化Hibernate的,使用Hibernate開發時,必須編寫該類。在類中編寫如下代碼(這里省略了import的內容):
package
public
private
private
static{
try
cf
sf
}
throw
}
}
public
Session
try
if
session
session
}
throw
}
return
}
public
try
if(session!=null)
session.close();
}
throw
}
}
public
getSession();
}
}
14.2 操作員工表
部門表的主鍵作為員工表的外鍵,所以在添加員工信息時,對應的部門信息要存在,否則拋出異常。這一節將介紹對員工表的增刪改查操作。
14.2.1 添加員工信息
在添加員工信息之前,首先在MySQL的控制台中或者客戶端工具中,往部門表中添加幾條數據。添加員工信息的頁面為addEmp.jsp,代碼如下(這里省略了html、head和body標簽,用省略號代替):
<%@
<!DOCTYPE
……
……
上述代碼中,from表單提交到AddEmpServlet中,使用post提交方式。頁面中有連個文本框,員工編號是自動增長的,所以不用添加。AddEmpServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
String
int
Emp
Dept
dept.setDepno(depno);//把depno設置到dept對象中
emp.setEmpname(empname);//把empname設置到emp對象中
emp.setDept(dept);//把dept設置到emp對象中
EmpDao
dao.addEmp(emp);//調用實現類的的添加方法
response.sendRedirect("ShowAllEmpServlet");//重定向到顯示全部的Servlet中
out.flush();
out.close();
}
}
編寫好Servlet以后,需要在WebRoot/WEB-INF/web.ml文件中配置Servlet信息。上述代碼中有這樣一行代碼:
EmpDao
其中EmpDao是一個接口,EmpDaoImp是接口實現類。這一行代碼是接口實現類的對象指向接口的引用。接口類EmpDao中代碼如下:
package
import
import
public
public
}
在接口實現類EmpDaoImp中實現addEmp方法。EmpDaoImp類的代碼如下(這里省略了import的內容):
package
public
Session
Transaction
public
session.save(emp);//添加數據
tr.commit();//提交事務
}
}
為了防止添加到數據庫中的數據出現中文亂碼,需要編寫一個處理中文亂碼的過濾器,過濾器的代碼如下:
package
import
import
public
public
//
}
public
FilterChain
request.setCharacterEncoding("gb2312");//設置request的編碼方式為gb2312
response.setCharacterEncoding("gb2312");//設置response的編碼方式為gb2312
chain.doFilter(request,
}
public
//
}
}
編寫好這些代碼以后,就可以正確的添加數據了。添加員工信息成功以后,頁面跳轉到ShowAllEmpServlet,所以添加數據的演示,放到顯示全部員工信息部分一起演示。
14.2.2 顯示全部員工信息
添加員工信息成功以后,頁面跳轉到ShowAllEmpServlet,該類是一個Servlet,用來顯示全部員工信息,ShowAllEmpServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
List<Emp>
EmpDao
list
request.setAttribute("list",
request.getRequestDispatcher("showAllEmp.jsp").forward(request,
out.flush();
out.close();
}
}
上述代碼中要在doGet方法中調用doPost方法,因為當頁面跳轉到Servlet中沒有特別說明,會進入doGet方法中。在doPost方法中調用了接口實現類EmpDaoImp的查詢全部方法queryAllEmp()方法。在接口EmpDao類中添加如下一行代碼:
public
在接口實現類EmpDaoImp類中實現queryAllEmp()方法,實現類EmpDaoImp中queryAllEmp()方法的代碼如下:
public
List<Emp>
tr.commit();//提交事務
return
}
在ShowAllEmpServlet中把查詢到的全部數據放入List集合中,再把List集合對象放入request對象中。然后轉發到顯示全部員工信息的頁面showAllEmp.jsp,showAllEmp.jsp頁面的代碼如下(這里省略了html、head和body標簽,用省略號代替):
<%@
<%@
<!DOCTYPE
……
<a
<a
</td>
……
在MyEclipse中啟動Toncat服務器,在IE瀏覽器的地址橫縱中輸入地址:“http://localhost:8080/hibernate_jsp/addEmp.jsp”,頁面效果如圖14.1所示。
圖14.1
在圖14.1所示的頁面中輸入員工姓名和閉門編號以后,單擊“提交”按鈕,數據添加成功以后進入圖14.2所示的頁面。
圖14.2
在圖14.2所示的頁面中,顯示了全部員工信息,同時提供了修改和刪除的操作。接下來介紹修改和刪除操作。
14.2.3 修改員工信息
修改數據的流程是:在頁面通過超鏈接跳轉顯示單條數據信息的頁面,在顯示單條數據信息的頁面中修改需要修改的數據,然后提交,把修改的數據提交到數據庫中。然后再次跳轉到顯示全部員工信息的頁面。
在圖14.2所示的頁面中,點擊“修改”插連接時,傳遞員工編號參數進入根據編號查詢的Servlet中(這里是QueryEmpById)。QueryEmpById的代碼如下(這里省略import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
Emp
EmpDao
emp
request.setAttribute("emp",
//轉發到現實單條記錄的頁面
request.getRequestDispatcher("showEmpById.jsp").forward(request,
out.flush();
out.close();
}
}
上述代碼中,在doGet()方法中調用doPost()方法,Servlet默認的進入的是doGet()方法,所以要在doGet()方法中調用doPost()方法。在doPost()方法中調用了實現類EmpDaoImp中的queryEmpById()方法。所以在接口EmpDao類中添加如下一行代碼:
public
在實現類EmpDaoImp中要實現queryEmpById(int
public
Emp
emp
return
}
查詢出數據以后,把數據放入request對象中,頁面轉發到顯示單條記錄的頁面showEmpById.jsp。showEmpById.jsp頁面的代碼如下(這里省略了html、head和body標簽,用省略號代替):
<%@
<%@
<!DOCTYPE
……
……
上述代碼中,form表單提交到UpdateEmpServlet,UpdateEmpServlet是一個修改數據的Servlet。UpdateEmpServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
String
int
Dept
Emp
dept.setDepno(depno);//設置depno到Dept的對象中
emp.setDept(dept);//設置dept到Emp對象中
emp.setEmpname(empname);//設置empname到Emp對象中
emp.setEmpno(empno);//設置empno到Emp對象中
EmpDao
dao.updateEmp(emp);//調用實現類的修改方法
response.sendRedirect("ShowAllEmpServlet");//重定向到查詢全部的Servlet
out.flush();
out.close();
}
}
該Servlet中的doGet方法調用doPost方法,修改的業務處理在doPost方法中處理。在doPost方法中,獲得頁面傳遞過來的數據以后,把數據設置到相應的對象中,調用了接口實現類EmpDaoImp中的修改方法。在接口EmpDao中添加修改方法updateEmp()方法,代碼如下:
public
在接口實現類EmpDaoImp中實現修改的方法,修改數據的方法updateEmp()方法的代碼如下:
public
session.update(emp);//修改
tr.commit();//提交事務
}
要修改數據,需要在顯示全部數據的頁面中,點擊修改超鏈接進入修改數據頁面。啟動Tomcat服務器,在IE瀏覽器地址欄中輸入地址:“http://localhost:8080/hibernate_jsp/ShowAllEmpServlet”,在顯示全部數據的頁面中點擊一個修改超鏈接,進入圖14.3所示的頁面。
圖14.3
在圖14.3所示的頁面中,員工編號是只讀的,不能修改。員工姓名和閉門編號可以修改。輸入修改后的數據,提交表單。修改成功后,頁面跳轉到圖14.4所示的頁面。
圖14.4
14.2.4 刪除員工信息
刪除員工信息的可以通過在圖14.4所示的頁面中點擊刪除超鏈接,進入刪除員工信息的Servlet,由Servlet調用刪除的方法,實現刪除員工信息的操作,刪除成功后,頁面跳轉到顯示全部員工信息的頁面。
刪除員工信息的Servlet——DeleteEmpById是處理刪除信息的Servlet,DeleteEmpById的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
EmpDao
dao.deleteEmp(empno);//調用實現類中的查詢方法
response.sendRedirect("ShowAllEmpServlet");//重定向到顯示全部員工信息頁面
out.flush();
out.close();
}
}
在DeleteEmpById類中的doGet方法中調用了doPost()方法,進入該Servlet時,默認進入的是doGet()方法,處理刪除的過程在doPost()方法中實現,該方法中調用了接口實現類中的刪除員工信息的方法,所以在接口EmpDao類中添加刪除員工信息的方法deleteEmp()方法,代碼如下:
public
在接口實現類EmpDaoImp中要實現deleteEmp()方法,deleteEmp()方法的代碼如下:
public
//使用Query對象來刪除
Query
query.setParameter("id",
query.executeUpdate();//刪除
tr.commit();//提交事務
}
刪除員工信息的代碼都寫好以后,可以在顯示全部數據的頁面中刪除需要刪除的員工信息,啟動Tomcat服務器,在IE瀏覽器地址欄中輸入地址:“http://localhost:8080/hibernate_jsp/ShowAllEmpServlet”,效果如圖14.5所示。
圖14.5
在圖14.5所示的頁面中刪除應改變好為2的員工信息。員工編號為2的員工姓名是小張,所在部門是Java開發部。刪除該條數據以后,進入圖14.6所示的頁面。
圖14.6
在圖14.6所示的頁面中可以看到,員工編號為2的數據已經被刪除了,這說明刪除員工信息成功。這里的刪除是單表刪除,在下一節操作部門表中會講到級聯刪除。
14.3 操作部門表
部門表的主鍵作為員工表的外鍵,所在在刪除部門表信息的時候,需要級聯刪除員工表信息。本節中將介紹部門表信息的添加、查詢和刪除。修改操作和員工表的修改方法類似,這里就不再重復。
14.3.1 添加部門信息
添加部門信息時在頁面中輸入部門信息,提交表單后由后台處理添加業務。添加部門的頁面addDept.jsp代碼如下(這里省略了html、head和body標簽,用省略號代替):
<%@
<!DOCTYPE
……
……
添加數據的表單提交到AddDeptServlet中,使用post方式提交表單內容。AddDeptServlet是處理添加數據層的Servlet,AddDeptServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
response.setCharacterEncoding("gb2312");//設置response編碼方式
request.setCharacterEncoding("gb2312");//設置request編碼方式
String
Dept
dept.setDepname(depname);//把獲得的頁面數據設置到Dept對象中
DeptDao
deptDao.addDept(dept);//調用實現類DeptDaoImp的addDept方法
response.sendRedirect("ShowAllDeptServlet");//頁面重定向到ShowAllDeptServlet中
out.flush();
out.close();
}
}
上述代碼中,在doPost()方法中獲得頁面表單提交的數據,然后調用接口實現類DeptDaoImp中的addDept方法。首先編寫接口DeptDao類,代碼如下:
package
import
import
public
public
}
在接口實現類DeptDaoImp中實現addDept()方法,接口實現類DeptDaoImp的代碼如下(這里省略了import的內容):
package
public
Session
Transaction
public
session.save(dept);//添加數據
tr.commit();//提交事務
}
}
在添加部門信息的Servlet中,添加數據成功以后,頁面跳轉到查詢全部數據的Servlet中,所以添加數據的演示留到和查詢全部數據一起演示。
14.3.2 查詢全部部門信息
添加部門信息成功以后,頁面跳轉到查詢全部部門信息的Servlet中,查詢全部部門信息的Servlet——ShowAllDeptServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
DeptDao
List<Dept>
list
request.setAttribute("list",
//轉發到顯示全部的頁面中
request.getRequestDispatcher("showAllDept.jsp").forward(request,
out.flush();
out.close();
}
}
在ShowAllDeptServlet的doGet()方法中調用了doPost()方法,查詢數據的操作的doPost()方法中處理。在doPost()方法中調用了接口實現類中的queryAllDept()方法。在接口DeptDao中添加queryAllDept()方法,代碼如下:
public
在接口實現類DeptDaoImp中實現queryAllDept()方法,queryAllDept()方法代碼如下:
public
//查詢全部部門信息
List<Dept>
eturn
}
查詢出全部的部門信息后,ShowAllDeptServlet轉發到顯示全部部門信息的頁面showAllDept.jsp中,showAllDept.jsp的代碼如下(這里省略了html、head和body標簽,用省略號代替):
<%@
<%@
<!DOCTYPE
……
……
現在來演示添加部門信息和查詢全部部門信息。啟動Tomcat服務器,在IE瀏覽器地址欄中輸入地址:“http://localhost:8080/hibernate_jsp/addDept.jsp”,頁面效果如圖14.7所示。
圖14.7
在圖14.7所示的頁面中輸入部門名稱后,提交表單。添加部門信息成功后頁面中顯示出全部的部門信息,效果如圖14.8所示。
圖14.8
14.3.3 刪除部門信息
部門表的主鍵是員工表的外鍵,在刪除部門信息時,如果該條信息是員工表一些數據的外鍵時,需要把員工表的信息業刪除掉。在編寫刪除操作之前,要在Dept.hbm.xml映射文件中設置一對多的級聯操作,<set>中的代碼修改成如下代碼:
在顯示全部部門信息的頁面中,點擊刪除超鏈接時,頁面進入刪除部門信息的Servlet——DeleteDeptServlet,DeleteDeptServlet的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
int
DeptDao
dao.deleteDept(depno);//調用刪除方法
response.sendRedirect("ShowAllDeptServlet");//頁面重定向到查詢全部部門信息的Servlet
out.flush();
out.close();
}
}
在DeleteDeptServlet的doGet()方法中調用了doPost()方法,doPost()方法中獲得路徑中傳遞的參數,然后調用接口實現類DeptDaoImp中的deleteDept()方法。在接口DeptDao中添加deleteDept()方法,代碼如下:
public
在接口實現類DeptDaoImp中要實現deleteDept()方法,deleteDept()方法代碼如下:
public
Dept
session.delete(dept);//刪除數據
session.flush();
tr.commit();//提交事務
}
刪除部門信息以后,該條信息對於的員工表外鍵數據也被刪除,啟動Tomcat服務器,在IE瀏覽器地址欄中輸入地址:“http://localhost:8080/hibernate_jsp/ShowAllDeptServlet”,頁面效果如圖14.9所示。
圖14.9
在圖14.9所示的頁面中刪除掉部門編號為2的數據,該條數據對應的部門名稱為市場部。刪除成功后,頁面進入圖14.10所示的頁面。
圖14.10
再到數據中查詢員工表的信息,發現外鍵為2的員工表信息都被刪除了,這是因為在刪除部門表信息時,使用了一對多的級聯刪除操作。
14.4 Hibernate的分頁查詢
當查詢結果時很多數據時,一個頁面無法全部顯示出來,這個時候就用到了分頁查詢。Hibernate的頁面查詢方法是必須要掌握的一個知識點。這一節將介紹簡單的Hibernate分頁查詢。為了便於理解,本節中的例子也采用分層來介紹,hql語句寫在數據庫訪問層(即DAO層),Servlet中調用DAO層代碼,在JSP頁面中分頁顯示出來。
14.4.1 數據庫訪問層代碼
數據庫訪問層也稱DAO層,在DAO層中,要定義兩個方法,一個方法是查詢數據信息的方法,一個方法是求最大頁數的方法。接口EmpPageDAO的代碼如下:
package
import
import
public
public
public
}
在接口中定義的方法,要在接口實現類EmpPageDAOImp中實現這些方法,接口實現類EmpPageDAOImp的代碼如下(這里省略了import的內容):
package
public
int
}
14.4.2 Servlet層的代碼
在數據庫訪問層中聲明了最大頁數和查詢數據信息的方法后,需要在Servlet中調用這些方法。這個例子中是在ShowEmpByPageServlet類中調用DAO層的方法,ShowEmpByPageServlet類的代碼如下(這里省略了import的內容):
package
public
public
throws
response.setContentType("text/html");
PrintWriter
this.doPost(request,
out.flush();
out.close();
}
public
throws
response.setContentType("text/html");
PrintWriter
String
int
int
if(page!=null){//如果獲得地址欄中的頁數不為null。賦值給pageNo
pageNo
}
EmpPageDAO
List<Emp>
//調用EmpPageDAOImp的getAll方法,獲得查詢結果
list
int
request.setAttribute("list",
request.setAttribute("page",
request.setAttribute("maxpage",
//轉發到showEmpByPage.jsp頁面
request.getRequestDispatcher("showEmpByPage.jsp").forward(request,
out.flush();
out.close();
}
}
在Servlet中調用接口實現類EmpPageDAOImp中的getAll()方法來獲得查詢信息,調用maxPage()方法來獲得最大頁數。把獲得的當前頁數、最大頁數和查詢結果放入request對象中,轉發到JSP頁面中。在JSP頁面獲得這些信息。
14.4.3 JSP頁面分頁
在JSP頁面中獲得Servlet轉發過來的數據信息后,分頁顯示出獲得的數據信息。在JSP頁面中使用到JSTL標簽庫來遍歷數據。分頁顯示的JSP頁面——showEmpByPage.jsp代碼如下:
<%@
<%@
<!DOCTYPE
<html>
<a
<a
</td>
<c:if
</html>
在showEmpByPage.jsp頁面中,如果當前頁面是第一頁,則首頁和上一頁變成不可點擊狀態,如果當前頁數是最大頁,則下一頁和末頁變成不可點擊狀態。啟動Tomcat服務器,在IE瀏覽器地址欄中輸入地址:“http://localhost:8080/hibernate_jsp/ShowEmpByPageServlet”,頁面效果如圖14.11所示。
圖14.11
14.5 本章小結
本章中使用Hibernate結合Servlet和JSP對數據庫表數據進行了操作。操作員工表時,添加數據涉及到部門表的信息,所以在添加員工信息時,要確保外鍵存在。在操作部門表時,刪除部門信息需要把員工表中有外鍵關聯的數據刪除,涉及到級聯刪除。本章好介紹了Hibernate的分頁查詢。