使用Struts的Action來(lái)通過(guò)Hibernate對(duì)數(shù)據(jù)庫(kù)進(jìn)行增、刪、改、查四項(xiàng)操作
Posted on 2005-08-14 18:08 風(fēng)太少 閱讀(1887) 評(píng)論(1) 編輯 收藏Struts Action的使用及開(kāi)發(fā)方法/模式
Hibernate的數(shù)據(jù)庫(kù)增、刪、改、查的編寫方法
Struts ActionForm Bean與Hibernate Maping Bean之間的轉(zhuǎn)換
Struts內(nèi)容的國(guó)際化
本文將不會(huì)涉及深入的Struts中的tag lib中的應(yīng)用,這方面的內(nèi)容大家可以參考技術(shù)天空的Chinese Struts項(xiàng)目中的相關(guān)文檔。
首先,請(qǐng)按照Hibernate開(kāi)發(fā)指南之環(huán)境準(zhǔn)備來(lái)準(zhǔn)備一個(gè)包含Hibernate和Struts的Web Project。 這個(gè)Web Project的名稱為:DBWebDemo。你可從這里下載這個(gè)空的Web Project,從這個(gè)項(xiàng)目來(lái)與我一起動(dòng)手開(kāi)始下面的工作。 你可以使用Eclipse的導(dǎo)入功能從zip文件中導(dǎo)入這個(gè)項(xiàng)目。
國(guó)際化資源文件
首先我們?yōu)檎军c(diǎn)準(zhǔn)備一個(gè)國(guó)際化的資源文件,這個(gè)資源文件將是站點(diǎn)用戶所使用的語(yǔ)言來(lái)決定的,如果Struts不能找到相對(duì)應(yīng)的語(yǔ)言資源文件,就會(huì)使用默認(rèn)的資源文件。 這里我們先會(huì)建立一個(gè)txt文件,將所有的中文信息寫入,再通過(guò)一個(gè)批處理或是shell腳本將該txt轉(zhuǎn)化成為Struts所使用的資源文件。這個(gè)方法并不是很好,但是我還不知在Eclipse中是否有更好的國(guó)際化插件。 如果你知道,請(qǐng)告訴我,我試用后會(huì)將相關(guān)的使用加入本節(jié)中。
建立原始的信息文件
在DBWebDemo項(xiàng)目的WEB-INF文件夾中建立一個(gè)新的文件夾,名為res,并在其中建立一個(gè)新文件,名為res_zh.txt,同時(shí)新建一個(gè)批處理文件名為genres.bat和一個(gè)shell腳本文件名為genres.sh:
這里我們給出genres.bat的內(nèi)容:
native2ascii -encoding GBK C:\...\web\WEB-INF\res\res_zh.txt > C:\...\DBWebDemo\src\...\ApplicationResources_zh_CN.properties
請(qǐng)使用你的文件的路徑來(lái)代替workspace之前的路徑。如果你有多種語(yǔ)言資源文件,加入多行,為每個(gè)文件準(zhǔn)備一個(gè)encode參數(shù),并使用該語(yǔ)言的后綴為ApplicationResources起名。
設(shè)置站點(diǎn)所使用的語(yǔ)言
我們使用一個(gè)Servlet的Filter來(lái)設(shè)置站點(diǎn)所使用的語(yǔ)言,我們可以將站點(diǎn)所使用的語(yǔ)言存在一個(gè)客戶端的cooke中,或是存于session中,還可以固定用戶必須使用中文。這里我們先固定用戶所使用的語(yǔ)言是中文。
建立SetEncodeFilter類
首先我們建立一個(gè)新的類名為SetEncodeFilter:
Filter接口會(huì)要求實(shí)現(xiàn)類實(shí)現(xiàn)以下方法:
init:初始化Filter時(shí)所做的工作
destroy:銷毀Filter時(shí)所做的工作
doFilter:當(dāng)有Servlet初調(diào)用時(shí)過(guò)濾的方法
我們先不寫這三個(gè)方法,先將這個(gè)Filter配置到Web應(yīng)用中去。
配置Web應(yīng)用使用Filter
首先我們打開(kāi)web.xml,在web-app的內(nèi)容中加入filter的聲明:
<filter>
<filter-name>Set Web Application Character Encoding</filter-name>
<filter-class> com.huangdong.dbwebdemo.SetEncodeFilter</filter-class>
<init-param>
<param-name>defaultencoding</param-name>
<param-value>gb2312</param-value>
</init-param>
</filter>
這里我們?cè)O(shè)置了過(guò)濾器的名稱和它的具體實(shí)現(xiàn)的類,還有就是為這個(gè)類配置了一個(gè)參數(shù),參數(shù)名為defaultencoding,它的值為gb2312。
為了使用這個(gè)過(guò)濾器,我們還要設(shè)置過(guò)濾器的作用范圍,在filter的聲明后加入以下內(nèi)容:
<filter-mapping>
<filter-name>Set Web Application Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
這里我們使用了/*這個(gè)通配符,意思是所有的servlet請(qǐng)求都會(huì)使用這個(gè)過(guò)濾器。接下來(lái),我們來(lái)書寫filter的實(shí)現(xiàn)代碼。
實(shí)現(xiàn)設(shè)置語(yǔ)言內(nèi)容過(guò)濾器
以下是過(guò)濾器的代碼內(nèi)容:
package com.huangdong.dbwebdemo;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @author HD
*/
public class SetEncodeFilter implements Filter {
/**
* 本過(guò)濾器的配置信息
*/
protected FilterConfig filterConfig = null;
/**
* 系統(tǒng)缺省的語(yǔ)言編碼
*/
protected String defaultencoding = null;
/**
* 初始化過(guò)濾器
*/
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
// 獲取系統(tǒng)缺省語(yǔ)言編碼
this.defaultencoding = filterConfig.getInitParameter("defaultencoding");
}
/**
* 過(guò)濾系統(tǒng)請(qǐng)求,設(shè)置請(qǐng)求的語(yǔ)言編碼
*/
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(selectEncoding(request));
chain.doFilter(request, response);
}
/**
* 過(guò)濾器銷毀
*/
public void destroy() {
this.defaultencoding = null;
this.filterConfig = null;
}
/**
* 選擇這次過(guò)濾所使用的語(yǔ)言編碼
* @param request 本次servlet請(qǐng)求的用戶request實(shí)例
* @return 選擇出的語(yǔ)言編碼
*/
protected String selectEncoding(ServletRequest request) {
// 可以在這里加入從request中取得session并從session中獲取用戶所選擇的encode
// 也可以在這里加入從request取得用戶客戶端的encode來(lái)設(shè)置當(dāng)前的語(yǔ)言編碼
return (this.defaultencoding);
}
}
代碼就不再一一解釋了,里面的注釋也說(shuō)的很清楚了。
加入Hibernate的相關(guān)配置
SessionFactory的初始化Struts Plugin
具體的加入方法這里就不再說(shuō)明,請(qǐng)大家參考Hibernate開(kāi)發(fā)指南之Plugin to Struts中的說(shuō)明,這里只是列出代碼:
package com.huangdong.dbwebdemo;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.cfg.Configuration;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
/**
* @author HD
*/
public class InitHibernatePlugin implements PlugIn {
/**
* 插件所獲取的容器上下文實(shí)例
*/
private Context ctx;
/**
* Hibernate初始化好的SessionFactory
*/
private SessionFactory sessionFactory;
/*
* 插件銷毀方法
*/
public void destroy() {
if (ctx != null) {
try {
// unbind JNDI 節(jié)點(diǎn)
ctx.unbind("HibernateSessionFactory");
} catch (NamingException e) {
e.printStackTrace();
}
}
if (this.sessionFactory != null) {
try {
// 關(guān)閉sessionFactory
sessionFactory.close();
} catch (HibernateException e) {
e.printStackTrace();
}
this.sessionFactory = null;
}
}
/*
* 插件初始化方法
*/
public void init(ActionServlet servlet, ModuleConfig config)
throws ServletException {
try {
// 獲取SessionFactory的實(shí)例
this.sessionFactory =
new Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException(
"Exception building SessionFactory: " + ex.getMessage(),
ex);
}
try {
// 取得容器上下文
ctx = new InitialContext();
// 將sessionFactory bind到JND樹(shù)中
ctx.bind("HibernateSessionFactory", this.sessionFactory);
} catch (NamingException ex) {
throw new RuntimeException(
"Exception binding SessionFactory to JNDI: " + ex.getMessage(),
ex);
}
}
}
session獲取工具類
另外為了配置Plugin的使用,我們還是使用一個(gè)與HibernateUtilPlus相同功能的類名為DBUtil類,以下為它的代碼:
package com.huangdong.dbwebdemo;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
/**
* @author HD
*/
public class DBUtil {
private static SessionFactory sessionFactory = null;
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
if (sessionFactory == null) {
// 如果sessionFactory實(shí)例為null則從JNDI中獲取
if (getSystemSessionFactory() == false) {
throw new HibernateException("Exception geting SessionFactory from JNDI ");
}
}
Session s = (Session) session.get();
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
private static boolean getSystemSessionFactory() {
try {
//從JNDI中取得SessionFactory的實(shí)例,如果出錯(cuò)返回false
Context inttex = new InitialContext();
sessionFactory =
(SessionFactory) inttex.lookup("HibernateSessionFactory");
} catch (NamingException e) {
return false;
}
return true;
}
}
Hibernate的配置文件
不要忘記我們還要將Hibernate的配置文件寫好(以下部分可以參見(jiàn)Hibernate開(kāi)發(fā)指南之環(huán)境準(zhǔn)備中相關(guān)的內(nèi)容):
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">net.sf.hibernate.dialect.Oracle9Dialect</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.username">hd</property>
<property name="connection.password">abc</property>
<property name="connection.url">jdbc:oracle:thin:@hdibm:1521:hdorc</property>
<property name="connection.pool.size">1</property>
<property name="statement_cache.size">25</property>
<property name="jdbc.fetch_size">50</property>
<property name="jdbc.batch_size">30</property>
<property name="show_sql">true</property>
<!-- Mapping files -->
<mapping resource="com/huangdong/demo/dao/SysUser.hbm.xml"/>
</session-factory>
</hibernate-configuration>
設(shè)置數(shù)據(jù)表實(shí)體化映射
這里我們還是使用之前幾篇文章的Oracle數(shù)據(jù)庫(kù)。所以連接配置都是差不多的。我們這次的增、刪、改、查還是使用SYSUSER表,所以還是使用顯示原來(lái)的map文件。以下是SysUser類的源代碼:
package com.huangdong.dbwebdemo.dao;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
/** @author Hibernate CodeGenerator */
public class SysUser implements Serializable {
/** identifier field */
private String userid;
/** persistent field */
private String username;
/** persistent field */
private String userpasword;
/** nullable persistent field */
private java.util.Calendar lastlogin;
/** full constructor */
public SysUser(
java.lang.String username,
java.lang.String userpasword,
java.util.Calendar lastlogin) {
this.username = username;
this.userpasword = userpasword;
this.lastlogin = lastlogin;
}
/** default constructor */
public SysUser() {
}
/** minimal constructor */
public SysUser(java.lang.String username, java.lang.String userpasword) {
this.username = username;
this.userpasword = userpasword;
}
public java.lang.String getUserid() {
return this.userid;
}
public void setUserid(java.lang.String userid) {
this.userid = userid;
}
public java.lang.String getUsername() {
return this.username;
}
public void setUsername(java.lang.String username) {
this.username = username;
}
public java.lang.String getUserpasword() {
return this.userpasword;
}
public void setUserpasword(java.lang.String userpasword) {
this.userpasword = userpasword;
}
public java.util.Calendar getLastlogin() {
return this.lastlogin;
}
public String getLastloginstr() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return df.format(this.lastlogin);
}
public void setLastlogin(java.util.Calendar lastlogin) {
this.lastlogin = lastlogin;
}
public String toString() {
return new ToStringBuilder(this)
.append("userid", getUserid())
.toString();
}
public boolean equals(Object other) {
if (!(other instanceof SysUser))
return false;
SysUser castOther = (SysUser) other;
return new EqualsBuilder()
.append(this.getUserid(), castOther.getUserid())
.isEquals();
}
public int hashCode() {
return new HashCodeBuilder().append(getUserid()).toHashCode();
}
}
還有映射的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.huangdong.dbwebdemo.dao.SysUser" table="SYSUSER">
<id column="userid" length="32" name="userid" type="string">
<generator class="uuid.hex"/>
</id>
<property column="username" length="20" name="username" not-null="true" type="string" unique="true"/>
<property column="userpasword" length="20" name="userpasword" not-null="true" type="string"/>
<property column="lastlogin" length="7" name="lastlogin" type="calendar"/>
</class>
</hibernate-mapping>
建立Struts的Action和Action FormBean
建立FormBean
在MyEclipse和Easy Struts中建立一個(gè)FormBean都是很簡(jiǎn)單的,首先打開(kāi)struts-config.xml文件,在大綱中選擇form-beans,新建:
然后在表單中按下圖輸入:
這樣我們就在com.huangdong.dbwebdemo.form包中新建了SysuserForm類。我們來(lái)為它加入相關(guān)的屬性,并設(shè)置geter和seter,以下是代碼:
package com.huangdong.dbwebdemo.form;
import org.apache.struts.action.ValidatorForm;
public class SysuserForm extends ValidatorForm {
// --------------------------------------------------------- Instance Variables
/** 用戶ID,只讀 */
private String userid;
/** 用戶名 */
private String username;
/** 用戶密碼 */
private String userpasword;
/** 最后登錄時(shí)間 */
private String lastlogin;
public SysuserForm() {
super();
}
public SysuserForm(SysUser sysuser) {
this.newSysuserForm(
sysuser.getUserid(),
sysuser.getUsername(),
sysuser.getUserpasword(),
sysuser.getLastloginstr());
}
public SysuserForm(
String userid,
String username,
String userpasword,
String lastlogin) {
this.newSysuserForm(userid, username, userpasword, lastlogin);
}
// --------------------------------------------------------- Methods
/**
* 為一個(gè)新的SysuserForm填充數(shù)據(jù)
*/
private void newSysuserForm(
String userid,
String username,
String userpasword,
String lastlogin) {
this.userid = userid;
this.username = username;
this.userpasword = userpasword;
this.lastlogin = lastlogin;
}
/**
* @return 最后登錄時(shí)間
*/
public String getLastlogin() {
return lastlogin;
}
/**
* @return 用戶ID
*/
public String getUserid() {
return userid;
}
/**
* @return 用戶名
*/
public String getUsername() {
return username;
}
/**
* @return 用戶密碼
*/
public String getUserpasword() {
return userpasword;
}
/**
* @param string 最后登錄時(shí)間,格式為YYYY-MM-DD hh:mm:ss
*/
public void setLastlogin(String string) {
lastlogin = string;
}
/**
* @param string 用戶名
*/
public void setUsername(String string) {
username = string;
}
/**
* @param string 用戶密碼
*/
public void setUserpasword(String string) {
userpasword = string;
}
/**
* 對(duì)提交的表單進(jìn)行校驗(yàn)
*/
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = super.validate(mapping, request);
return errors;
}
}
這里我們看到我們?cè)揊ormBean加入了數(shù)據(jù)校驗(yàn)的功能,在下面會(huì)仔細(xì)說(shuō)明。同時(shí)為了與Hibernate的數(shù)據(jù)庫(kù)進(jìn)行轉(zhuǎn)換加入了相關(guān)的構(gòu)造器和私有方法。
建立第一個(gè)Action
在struts-config.xml中加入action的定義,如下:
<action name="sysuserForm"
path="/sysuser"
type="com.huangdong.dbwebdemo.action.SysuserAction"
scope="request"
input="/sysuser/editsysuser.jsp">
<forward name="create" path="/sysuser/editsysuser.jsp"/>
</action>
這里我們來(lái)說(shuō)明一下,name和attribute說(shuō)明了本action所使用的FormBean的名稱, path指定了調(diào)用action的URL頭,type則指明了該action實(shí)現(xiàn)的具體類, scope說(shuō)明了FormBean所存活的區(qū)域,而input則說(shuō)明了輸入數(shù)據(jù)的View的地址(實(shí)質(zhì)上是校驗(yàn)有問(wèn)題里指到的View)。 在最后的forward定義中則定義了一系列的action可能會(huì)用到的View指向,這里我們只指定了一個(gè),后面會(huì)一個(gè)個(gè)的加入進(jìn)來(lái)。
接著在com.huangdong.dbwebdemo.action包中新建SysuserAction類:
package com.huangdong.dbwebdemo.action;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
import com.huangdong.dbwebdemo.form.SysuserForm;
public class SysuserAction extends Action {
// --------------------------------------------------------- Instance Variables
// --------------------------------------------------------- Methods
/**
* Method execute
* @param ActionMapping mapping
* @param ActionForm form
* @param HttpServletRequest request
* @param HttpServletResponse response
* @return ActionForward
* @throws Exception
*/
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// 初始化系統(tǒng)語(yǔ)言資源
Locale locale = getLocale(request);
MessageResources messages = getResources(request);
// 本action默認(rèn)接收的處理請(qǐng)求為創(chuàng)建一個(gè)新的SYSUSER
String action = "create";
return (mapping.findForward(action));
}
}
這里頭兩句代碼是用于設(shè)置View所使用的本地消息資源文件語(yǔ)言代碼的。
將VO與PO關(guān)聯(lián)
VO與PO的關(guān)系
VO即業(yè)務(wù)層的數(shù)據(jù)表示,而PO即持久層的數(shù)據(jù)表示。VO會(huì)在View和業(yè)務(wù)處理時(shí)大量使用,也就是說(shuō),所有沒(méi)有入庫(kù)前的數(shù)據(jù)都會(huì)存儲(chǔ)于一個(gè)個(gè)的VO中。而PO則是數(shù)據(jù)庫(kù)在Java中的持久數(shù)據(jù)結(jié)構(gòu)。
有許多人喜歡將Struts的VO與Hibernate的PO合并起來(lái),我不同意,原因很多,最重要的有以下幾點(diǎn):
VO有自己的數(shù)據(jù)屬性,同時(shí)因框架的不同可能會(huì)有自己的結(jié)構(gòu)和方法,在Struts中我喜歡用FormBean來(lái)做VO,它就是擴(kuò)展ActionForm的一個(gè)類
VO中還會(huì)有大量的業(yè)務(wù)操作方法,如校驗(yàn)、自動(dòng)生成等方法
PO中會(huì)包含數(shù)據(jù)集之間的關(guān)系,如數(shù)據(jù)庫(kù)中的關(guān)系也會(huì)體現(xiàn)在PO中的一對(duì)一、多對(duì)多、一對(duì)多等,而在VO中不一定關(guān)注這樣的細(xì)節(jié)
總之,我更喜歡使用一個(gè)或多個(gè)關(guān)聯(lián)的類將業(yè)務(wù)邏輯中的VO與PO對(duì)映起來(lái),實(shí)現(xiàn)VO到PO的轉(zhuǎn)換,以及PO中VO的取出。
VO與PO操作的抽像類
所有VO到PO的操作基本上都會(huì)是持久層數(shù)據(jù)的存入或更改(刪除)。這樣的操作一定會(huì)涉及到數(shù)據(jù)庫(kù)的事務(wù)操作。另一方面,PO到VO的數(shù)據(jù)取出涉及到的則是數(shù)據(jù)集合的緩沖、分頁(yè)、過(guò)涉等技巧。所以我們?yōu)檫@兩種情況聲明兩個(gè)抽像類:
AbsBaseMap類主要完成VO到PO的數(shù)據(jù)操作:
package com.huangdong.dbwebdemo.db;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;
import com.huangdong.dbwebdemo.DBUtil;
/**
* 系統(tǒng)VO與PO的操作映射器抽像類,完成數(shù)據(jù)庫(kù)事務(wù)和連接的初始化以及數(shù)據(jù)庫(kù)事務(wù)的提交及數(shù)據(jù)庫(kù)連接的關(guān)閉
* @author HD
*/
public abstract class AbsBaseMap {
// 數(shù)據(jù)庫(kù)連接session
private Session session;
// 數(shù)據(jù)庫(kù)事務(wù)處理器
private Transaction transaction;
/**
* 初始化數(shù)據(jù)庫(kù)連接事務(wù)
* @return 初始化完成的數(shù)據(jù)庫(kù)連接
* @throws HibernateException
*/
public Session beginTransaction() throws HibernateException {
session = DBUtil.currentSession();
transaction = session.beginTransaction();
return session;
}
/**
* 完成一個(gè)數(shù)據(jù)庫(kù)事務(wù)
* @param commit 是否提交事務(wù),true時(shí)提交,false時(shí)向數(shù)據(jù)庫(kù)發(fā)起回滾(rollback)
* @throws HibernateException
*/
public void endTransaction(boolean commit) throws HibernateException {
if (commit) {
transaction.commit();
} else {
transaction.rollback();
}
DBUtil.closeSession();
}
}
AbsQueryMap類則主要提供了有關(guān)持久層數(shù)據(jù)的查詢的抽像方法:
package com.huangdong.dbwebdemo.db;
/**
* 系統(tǒng)VO與PO的查詢映射抽像類,加入查詢的分頁(yè)相關(guān)設(shè)置
* @author HD
*/
public class AbsQueryMap {
/**
* 數(shù)據(jù)庫(kù)連接session
**/
Session session;
// 分頁(yè)為20
int pagesize = 20;
// 當(dāng)前頁(yè)數(shù)
int pageno = 1;
/**
* @return 分頁(yè)行數(shù)大小(默認(rèn)為20)
*/
public int getPagesize() {
return pagesize;
}
/**
* @param i 設(shè)置分頁(yè)行數(shù)大小
*/
public void setPagesize(int i) {
pagesize = i;
}
/**
* @return 返回當(dāng)前頁(yè)號(hào),初始值為1
*/
public int getPageno() {
return pageno;
}
/**
* @param i 設(shè)置當(dāng)前頁(yè)號(hào)
*/
public void setPageno(int i) {
pageno = i;
}
/**
* 設(shè)置查詢分頁(yè)
*/
public void setQueryPage(Query query) {
// 設(shè)置分頁(yè)起始記錄號(hào)
query.setFirstResult((this.pageno - 1) * this.pagesize);
// 設(shè)置頁(yè)內(nèi)數(shù)據(jù)量
query.setMaxResults(this.pagesize);
}
/**
* 打開(kāi)當(dāng)前的數(shù)據(jù)庫(kù)連接
* @return
* @throws HibernateException
*/
public void initSession() throws HibernateException {
this.session = DBUtil.currentSession();
}
/**
* 關(guān)閉當(dāng)前的數(shù)據(jù)庫(kù)連接
* @throws HibernateException
*/
public void closeSession() throws HibernateException {
DBUtil.closeSession();
}
}
以后,我們所有的數(shù)據(jù)庫(kù)更新操作都會(huì)繼承AbsBaseMap類,而數(shù)據(jù)庫(kù)查詢操作會(huì)繼承AbsQueryMap類。
數(shù)據(jù)庫(kù)增、刪、改操作映射
一旦有了上節(jié)所提供的AbsBaseMap抽像類和Hibernate所提供的功能,我們只需要了解一點(diǎn)點(diǎn)Java的知識(shí)就可以完成復(fù)雜的數(shù)據(jù)庫(kù)更新功能了。
首先在com.huangdong.dbwebdemo.db包中新建一個(gè)類名為SysUserMap并擴(kuò)展AbsBaseMap類:
package com.huangdong.dbwebdemo.db;
import com.huangdong.dbwebdemo.form.SysuserForm;
public class SysUserMap extends AbsBaseMap {
}
先來(lái)實(shí)現(xiàn)一個(gè)增加的方法,在VO層,我們使用的數(shù)據(jù)類為SysuserForm,所以增加方法的參數(shù)一定是SysuserForm:
public void createSysUser(SysuserForm sysuerForm)
throws HibernateException {
// 使用sysuerForm的相關(guān)屬性新建sysuser實(shí)例
SysUser sysuser =
new SysUser(
sysuerForm.getUsername(),
sysuerForm.getUserpasword(),
Calendar.getInstance());
// 啟動(dòng)事務(wù)
Session session = this.beginTransaction();
try {
// 新增這個(gè)實(shí)例到數(shù)據(jù)庫(kù)中
session.save(sysuser);
// commit
this.endTransaction(true);
} catch (HibernateException e) {
// rollback
this.endTransaction(false);
throw e;
}
}
這個(gè)方法已經(jīng)非常的簡(jiǎn)單了,書寫者完全可以不用理會(huì)數(shù)據(jù)庫(kù)相關(guān)的內(nèi)容了。
接著我們來(lái)寫更新的代碼,相比之下一樣的簡(jiǎn)單:
/**
* 更新一個(gè)sysuser
* @param sysuerForm 包含更新內(nèi)容的sysuser form bean
* @throws HibernateException
*/
public void updateSysUser(SysuserForm sysuerForm)
throws HibernateException {
// 使用sysuerForm的相關(guān)屬性新建sysuser實(shí)例
SysUser sysuser =
new SysUser(
sysuerForm.getUsername(),
sysuerForm.getUserpasword(),
Calendar.getInstance());
// 啟動(dòng)事務(wù)
Session session = this.beginTransaction();
try {
// 新增這個(gè)實(shí)例到數(shù)據(jù)庫(kù)中
session.update(sysuser);
// commit
this.endTransaction(true);
} catch (HibernateException e) {
// rollback
this.endTransaction(false);
}
}
下面我們來(lái)寫一個(gè)內(nèi)容更多一些的代碼--刪除。刪除一般都會(huì)是使用用戶ID來(lái)刪除,所以參數(shù)可以是帶有用戶ID的formbean或是用戶ID,我們使用兩個(gè)方法來(lái)實(shí)現(xiàn)刪除:
/**
* 依據(jù)一個(gè)sysuser formbean來(lái)刪除該用戶
* @param sysuerForm 包含該用戶信息的Form Bean
* @throws HibernateException
*/
public void deleteSysUser(SysuserForm sysuerForm)
throws HibernateException {
String userid = sysuerForm.getUserid();
this.deleteSysUser(userid);
}
/**
* 依據(jù)用戶ID來(lái)刪除該用戶
* @param userid 用戶ID
* @throws HibernateException
*/
public void deleteSysUser(String userid) throws HibernateException {
Session session = this.beginTransaction();
try {
// 先向數(shù)據(jù)庫(kù)中查詢是否有這個(gè)用戶
SysUser sysuser = (SysUser) session.load(SysUser.class, userid);
// 干掉它!
session.delete(sysuser);
this.endTransaction(true);
} catch (HibernateException e) {
this.endTransaction(false);
}
}
數(shù)據(jù)庫(kù)簡(jiǎn)單查詢
數(shù)據(jù)庫(kù)的查詢相對(duì)復(fù)雜一些了,我們從簡(jiǎn)單做起,先不使用任何備件,查詢數(shù)據(jù)庫(kù)中所有的記錄。在com.huangdong.dbwebdemo.db中新建SysUserQueryMap類,它擴(kuò)展AbsQueryMap抽像類:
package com.huangdong.dbwebdemo.db;
import java.util.Iterator;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
/**
* @author HD
*/
public class SysUserQueryMap extends AbsQueryMap {
public SysUserQueryMap() throws HibernateException {
this.initSession();
}
public Iterator findAllSysUser() throws HibernateException {
// 查詢語(yǔ)句
String querystr = "from SysUser";
// 創(chuàng)建查詢
Query query = this.session.createQuery(querystr);
// 設(shè)置分頁(yè)
this.setQueryPage(query);
// 返回查詢出的結(jié)果集
return query.iterate();
}
}
這里我們已經(jīng)寫好一個(gè)查詢所有的用戶的方法,它的第一句:
String querystr = "from SysUser";
這里的查詢語(yǔ)句使用了Hibernate的HQL語(yǔ)法,別的我們先不用管,這里SysUser是區(qū)分大小寫的,我們之前定義了SysUser數(shù)據(jù)庫(kù)映射類,這里必須完全一樣,這樣Hibernate就會(huì)從數(shù)據(jù)庫(kù)中取出所有SysUser類的實(shí)例。
接下來(lái)我們還需要一個(gè)方法能夠按照用戶的id返回其所對(duì)應(yīng)的用戶。
/**
* 查詢出一個(gè)UserID的用戶實(shí)例
* @param UserID 用戶的UserID
* @return 用戶實(shí)例,如果數(shù)據(jù)庫(kù)無(wú)相應(yīng)記錄返回null
* @throws HibernateException
*/
public SysuserForm getSysuserByID(String UserID)
throws HibernateException {
SysuserForm sysuerform = null;
try {
sysuerform =
new SysuserForm(
(SysUser) this.session.load(SysUser.class, UserID));
} catch (HibernateException e) {
throw e;
}
return sysuerform;
}
有了這個(gè)方法,我們才能對(duì)指定用戶進(jìn)行查詢,或者對(duì)他已有的信息進(jìn)行修改。
創(chuàng)建第一個(gè)View
新建JSP頁(yè)面
我們先為增加記錄建立一個(gè)JSP頁(yè)面,它提供了增加記錄的View。
<head>
<html:base />
<title><bean:message key="title.register"/></title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<logic:notEmpty name="sysuserForm" property="username" scope="request">
<html:errors />
</logic:notEmpty>
<html:form action="/sysuser.do" method="post" focus="login" onsubmit="return validateSysuserForm(this);">
<table border="0">
<tr>
<td>
<bean:message key="prompt.login"/>
</td>
<td>
<html:text property="username" size="16" maxlength="16"/>
</td>
</tr>
<tr>
<td>
<bean:message key="prompt.password"/>
</td>
<td>
<html:password property="userpasword" />
</td>
</tr>
<logic:notEmpty name="sysuserForm" property="lastlogin" scope="request">
<td>
<html:hidden property="lastlogin" write="true"/>
</td>
</logic:notEmpty>
<tr>
<td colspan="2" align="center">
<logic:empty name="sysuserForm" property="userid" scope="request">
<input type="hidden" name="act" value="add"/>
</logic:empty>
<logic:notEmpty name="sysuserForm" property="userid" scope="request">
<input type="hidden" name="act" value="update"/>
</logic:notEmpty>
<html:submit>
<bean:message key="button.submit"/>
</html:submit>
</td>
</tr>
</table>
</html:form>
<html:javascript formName="sysuserForm"
dynamicjavascript="true"
staticjavascript="false"/>
<script language="javascript1.1" src="../staticjavascript.jsp"/></script>
</body>
</html:html>
有關(guān)這個(gè)JSP頁(yè)面中的各種taglib的使用在這里我們就不深入講解, 你可以到技術(shù)天空的Chinese Struts項(xiàng)目網(wǎng)站了解這些tag的使用。 我們只對(duì)一些我們關(guān)心的內(nèi)容做一些說(shuō)明。
首先我們使用了html:errors這個(gè)tag來(lái)顯示可能出現(xiàn)的錯(cuò)誤信息, 在后面我們的Action加工中我們會(huì)向errors中加入我們的數(shù)據(jù)校驗(yàn)、后臺(tái)操作產(chǎn)生的錯(cuò)誤,在這里通過(guò)這個(gè)tag來(lái)顯示出來(lái)。 這個(gè)表單的action="/sysuser.do"說(shuō)明提交還是提交到了sysuser這個(gè)action,因?yàn)榫唧w的增加方法也會(huì)是在這個(gè)action中完成。 表單的屬性最后有一個(gè)onsubmit="return validateSysuserForm(this);",是用于驗(yàn)證每個(gè)輸入條目的正確的,具體這里的定義我們會(huì)在稍后一些說(shuō)明。 在表單的最后我們使用logic這個(gè)tag來(lái)判斷sysuserForm中的userid是否存在,在確定表單中act這個(gè)參數(shù)的默認(rèn)值是add還是edit。 這么做的原因是我們還將使用這個(gè)jsp用于用戶信息的編輯。 在整個(gè)頁(yè)面的最后,我們使用了html:javascript這個(gè)tag將sysuserForm所使用到的校驗(yàn)javascript生成出來(lái)。 為了優(yōu)化資源的使用,我們將所有的校驗(yàn)javascript放在一個(gè)jsp中,也在最后使用javascript的引用標(biāo)簽引用進(jìn)來(lái)了。
View公用的校驗(yàn)javascript代碼頁(yè)
下面我們列出staticjavascript.jsp的內(nèi)容:
<%@ page language="java" %>
<%-- set document type to javascript (addresses a bug in Netscape according to a web resource --%>
<%@ page contentType="application/x-javascript" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:javascript dynamicjavascript="false" staticjavascript="true"/>
這個(gè)JSP則是使用了struts所帶的校驗(yàn)組件來(lái)生成了校驗(yàn)所使用的所有javascript。
將業(yè)務(wù)邏輯關(guān)聯(lián)起來(lái)
為Action加入處理
這個(gè)Action會(huì)處理的是與SYSUSER相關(guān)的所有操作,所以action會(huì)接收到的請(qǐng)求和顯示的表單會(huì)有多個(gè),我們?cè)趀xecute方法中加入以下的代碼:
if (action.equals("create")) {
// 如果處理請(qǐng)求類型為create
request.setAttribute("sysuserForm", new SysuserForm());
action = "create";
} else if (action.equals("add")) {
// 如果處理請(qǐng)求類型為add
SysUserMap sysusermap = new SysUserMap();
try {
sysusermap.createSysUser(sysuser);
// 加入成功,我們先再接著加下一個(gè)用戶
request.setAttribute("sysuserForm", new SysuserForm());
action = "create";
} catch (HibernateException e) {
// 數(shù)據(jù)庫(kù)存入出錯(cuò)
ActionErrors errors = new ActionErrors();
errors.add(
ActionErrors.GLOBAL_ERROR,
new ActionError("error.database.save", e.toString()));
this.saveErrors(request, errors);
//將當(dāng)前數(shù)據(jù)回顯,并顯示讓用戶重新輸入
request.setAttribute("sysuserForm", sysuser);
action = "create";
}
這個(gè)業(yè)務(wù)操作很簡(jiǎn)單,主要是調(diào)用Map來(lái)將VO的數(shù)據(jù)存入PO中,完成一個(gè)向數(shù)據(jù)庫(kù)中增加一條記錄的功能。 我們的具體實(shí)現(xiàn)是先創(chuàng)建了一個(gè)新的FormBean來(lái)存放用戶的輸入,之后將FormBean中的數(shù)據(jù)存入數(shù)據(jù)庫(kù)中。 在存入時(shí)如果出現(xiàn)錯(cuò)誤,我們將這個(gè)exception的內(nèi)容打入error中,在jsp中去顯示(可以回頭看看jsp中的內(nèi)容)。
接下來(lái),我們完成刪、改、查的功能,這些操作也是很簡(jiǎn)單的。
if (action == null || action.equals("list")) {
//如果處理請(qǐng)求類型為list
SysUserQueryMap sqm = new SysUserQueryMap();
Iterator sysuserlist = sqm.findAllSysUser();
request.setAttribute("sysuserlist", sysuserlist);
action = "list";
}
這段代碼定義了在默認(rèn)的情況下或者請(qǐng)求list操作的時(shí)候,完成列出所有用戶的操作。 實(shí)際就是調(diào)用了我們?cè)谇懊嫱瓿傻腟ysUserQueryMap中的findAllSysUser的方法從數(shù)據(jù)庫(kù)中取出了所有的用戶。 之后將用戶列表壓入了bean中。
if (action.equals("edit")) {
// 請(qǐng)求類型為edit
SysUserQueryMap sqm = new SysUserQueryMap();
String uid = request.getParameter("userid");
request.setAttribute("sysuserForm",sqm.getSysuserByID(uid));
} else if (action.equals("update")){
// 請(qǐng)求類型為update
SysUserMap sysusermap = new SysUserMap();
sysusermap.updateSysUser(sysuser);
action = "list";
}
這段代碼完成了編輯用戶數(shù)據(jù)的工作。我們可以看出首先需要完成一個(gè)edit工作, 這個(gè)操作的作用是從數(shù)據(jù)庫(kù)中取得這個(gè)用戶的信息,然后將這個(gè)用戶信息壓入FormBean中,供頁(yè)面進(jìn)行顯示。 在用戶對(duì)信息進(jìn)行更改之后則完成update操作,對(duì)數(shù)據(jù)庫(kù)條目進(jìn)行更新。
if (action.equals("delete")) {
// 如果處理請(qǐng)求類型為delete
SysUserMap sysusermap = new SysUserMap();
String uid = request.getParameter("userid");
try {
sysusermap.deleteSysUser(uid);
} catch (HibernateException e) {
ActionErrors errors = new ActionErrors();
errors.add(
ActionErrors.GLOBAL_ERROR,
new ActionError("error.database.delete", e.toString()));
this.saveErrors(request, errors);
}
action = "list";
}
這段代碼完成刪除的功能。刪除指定的條目。如果出錯(cuò)就壓一個(gè)錯(cuò)誤到全局的錯(cuò)誤中。
對(duì)表單輸入的數(shù)據(jù)做校驗(yàn)
在struts中帶有了Jakarta Commons中的一個(gè)叫做Validator的數(shù)據(jù)校驗(yàn)框架。 使用起來(lái)也是非常的簡(jiǎn)單。
首先將struts提供的validator-rules.xml的配置文件放入WEB-INF中。
然后在struts-config.xml中加入validation的plugin聲明:
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
我們會(huì)看到還有一個(gè)validator.xml文件不存在,在WEB-INF中新建這個(gè)xml文件,我們需要在其中加入自己的校驗(yàn)信息:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE form-validation PUBLIC
"-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"
"http://jakarta.apache.org/commons/dtds/validator_1_0.dtd">
<form-validation>
<formset>
<form name="sysuserForm">
<field property="username"
depends="required, minlength,maxlength">
<arg0 key="prompt.login"/>
<arg1 key="${var:minlength}" name="minlength"
resource="false"/>
<arg2 key="${var:maxlength}" name="maxlength"
resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>3</var-value>
</var>
</field>
<field property="userpasword"
depends="required, minlength,maxlength">
<arg0 key="prompt.password"/>
<arg1 key="${var:minlength}" name="minlength"
resource="false"/>
<arg2 key="${var:maxlength}" name="maxlength"
resource="false"/>
<var>
<var-name>maxlength</var-name>
<var-value>16</var-value>
</var>
<var>
<var-name>minlength</var-name>
<var-value>3</var-value>
</var>
</field>
</form>
</formset>
</form-validation>
仔細(xì)的看看這個(gè)xml文件的內(nèi)容就會(huì)發(fā)現(xiàn)它說(shuō)明要校驗(yàn)的表單名為sysuserForm, 并對(duì)這個(gè)表單中的幾個(gè)需要做校驗(yàn)的字段一一做了校驗(yàn)方法說(shuō)明。 具體Validator的使用請(qǐng)參考它帶的相關(guān)文檔和struts的相關(guān)說(shuō)明。
注意:如果使用默認(rèn)的檢查規(guī)則對(duì)表單進(jìn)行檢查的話需要注意幾個(gè)關(guān)鍵的地方,否則你可能就會(huì)花很長(zhǎng)的時(shí)間檢查js腳本無(wú)法應(yīng)用的原因。 首先您所使用的FormBean就不能是原來(lái)的ActionForm了,需要更改為ValidatorForm。 這個(gè)Form中還必須有一個(gè)類似這樣的validate方法:
public ActionErrors validate(
ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = super.validate(mapping, request);
return errors;
}
其次需要在頁(yè)面的結(jié)尾處聲明使用javascript:
<html:javascript formName="sysuserForm"
dynamicjavascript="true"
staticjavascript="false"/>
dynamicjavascript屬性是代表是否在頁(yè)面內(nèi)生成動(dòng)態(tài)的js腳本。 如果您要對(duì)表單進(jìn)行合法性檢查的話,此屬性必須為true。 staticjavascript屬性代表是否在頁(yè)面內(nèi)生成靜態(tài)js腳本。 如果您設(shè)為true,則存放在validator-rules.xml文件中的規(guī)則檢查js 都將填充到本頁(yè)面內(nèi)。這樣做的效果不是很好,因?yàn)闀?huì)使頁(yè)面變得很大, 并且消耗大量的額外資源。通常的做法是將此選項(xiàng)設(shè)置成false, 將validator-rules.xml中的js填充到一個(gè)指定的jsp頁(yè)面中去。 這樣多個(gè)表單都可以同時(shí)使用一個(gè)靜態(tài)頁(yè)面,從而節(jié)省大量的資源。 如果這樣做我們就需要在后面在聲明對(duì)這個(gè)靜態(tài)頁(yè)面進(jìn)行引用。
<script language="javascript1.1" src="../staticjavascript.jsp"/></script>
書寫這句話的時(shí)候也需要注意一點(diǎn),盡量使用相對(duì)路徑較好。 使用絕對(duì)路徑的時(shí)候很難準(zhǔn)確的定位這個(gè)靜態(tài)頁(yè)面的位置。
最后需要注意的一點(diǎn)就是在引用這個(gè)js檢查的時(shí)候。
<html:form action="/sysuser.do" method="post" focus="login" onsubmit="return validateSysuserForm(this);">
return validateSysuserForm(this);這個(gè)函數(shù)的名字是根據(jù)你所檢查的表單的名字而改變的。 例如我們檢查的這個(gè)表單叫做sysuserForm,則生成的檢查函數(shù)的名字為validateSysuserForm。 您在使用的時(shí)候需要將其修改成跟您所需要檢查的表單相對(duì)應(yīng)的函數(shù)名,否則js的檢查就形同虛設(shè)了。
附錄
最后我們提供我們這篇文章所使用的例子的完整項(xiàng)目給大家下載。 您可以方便的將這個(gè)項(xiàng)目導(dǎo)入到您的eclipse中去。
轉(zhuǎn)自http://bsd.huangdong.com/dev/hibernate/strutsaction/index.html