首先:我們需要搭建SSH環(huán)境,在這里,我們選擇使用Myeclipse自帶的導(dǎo)航為我們添加框架支持。接下來,我會一步步教大家做。
1.新建一個工程項目
2.添加Hibernate框架支持
A.myeclipse--project capabilities--add Hibernate capabilities
B.在這里,使用Hibernate3.3版本,默認情況下添加核心包和注解包,注意,勾選最下面選項,將jar自動添加到lib目錄,方便換了電腦后修改。
C.這一步,按照默認點擊next,生成的配置文件,我們可能不會使用到,因為我們整合了Spring。
D.忽略數(shù)據(jù)庫連接的創(chuàng)建
E.不使用Hibernate幫我們創(chuàng)建SessionFactory,Spring會幫助我們創(chuàng)建
到此為止,Hibernate的配置就完成了,下面我們來進行Spring的配置。
3.添加Spring框架支持
A.在這里我們使用Spring2.5的版本,所添加的jar包括以下5個(截圖為4個,還有一個為Spring2.5 web libray)別忘記把jar添加到lib目錄。
B.創(chuàng)建的Spring配置文件applicationContext.xml一般不用改名字,但目錄建議改為webroot/WEB-INF下,因為Spring加載配置文件默認從那里開始
C.接下來一步,一般不需要選擇,我們自己編寫代碼來創(chuàng)建SessionFactory
到目前為止,我們基本上把Spring也配置完成了,觀察我們的包結(jié)構(gòu),會發(fā)現(xiàn)多了一些標(biāo)記,如‘S’等,意味著我們已經(jīng)成功添加了Spring框架。接下來我們添加Struts框架支持,myeclipse沒有為我們提供導(dǎo)航,你可以下載相關(guān)插件,但也不必要因為配置Struts的框架比較簡單,手動添加就可以了。
4.添加Struts框架支持。
A.導(dǎo)入Struts2.2相關(guān)架包,注意不要忘記Struts2=Spring-plugin.jar這個包,它是框架整合需要用到的。
B.創(chuàng)建一個Struts的配置文件Struts.xml,可以直接拷貝之前項目的。(截圖略)
C.配置Struts的啟動參數(shù),在web.xml配置相關(guān)信息,如下:
D.同時,我們注冊Spring的監(jiān)聽器,一樣是在web.xml文件下
<!-- 配置Spring監(jiān)聽器 -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
有同學(xué)要問為什么不配置Spring配置文件的加載路徑,因為之前我們已經(jīng)修改過路徑為Spring默認的加載路徑,所以在這里我們不需要指定,但是如果你自定義了配置文件在src目錄下,你需要配置如下信息:
<!-- 指定spring的配置文件,默認從web根目錄尋找配置文件,我們可以通過spring提供的classpath:前綴指定從類路徑下尋找 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
到目前為止,我們已經(jīng)成功的為我們的項目添加了SSH的框架支持,接下來我們可以加載一遍服務(wù)器,啟動服務(wù)器,運行一下我們的這個小系統(tǒng),看是否能跑起來。(截圖略)如果沒有異常,表示大功告成。
5.配置Spring的applicationContext.xml文件
在配置之前,必要說明一點:在這里我們使用的是sql server 2005作為后臺數(shù)據(jù)庫,所以要加入相關(guān)的驅(qū)動,我們在這里選用jtds驅(qū)動,當(dāng)然你可以使用其它,比如jdbc等,此時我們還需要導(dǎo)入jtds的架包:jtds-1.2.jar.
A.在Spring的配置文件中,我們首先配置數(shù)據(jù)源:
<!--
配置數(shù)據(jù)源
驅(qū)動:jtds
數(shù)據(jù)庫:sql server 2005
username : sa
password : 123
-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"></property>
<property name="url" value="jdbc:jtds:sqlserver://localhost:1433/oa;characterEncoding=UTF-8"></property>
<property name="username" value="sa"></property>
<property name="password" value="123"></property>
<property name="maxActive" value="100"></property>
<property name="maxIdle" value="30"></property>
<property name="maxWait" value="500"></property>
<property name="defaultAutoCommit" value="true"></property>
</bean>
B.然后我們配置會話工廠SessionFactory:相關(guān)屬性不做介紹,在這里主要mappingResource這個屬性,我們填寫的就是我們要操作的實體對象,在這里我們要對一個User對象進行操作,所以我們需要創(chuàng)建一個User類,把這個對象映射到數(shù)據(jù)庫當(dāng)中。
<!-- 會話工廠 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<!-- 數(shù)據(jù)庫方言 -->
<prop key="hibernate.dialect">org.hibernate.dialect.SybaseDialect</prop>
<!-- 顯示sql語言 -->
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<!-- 映射文件 -->
<property name="mappingResources">
<list>
<value>cn/zbvc/bean/User.hbm.xml</value>
</list>
</property>
</bean>
6..現(xiàn)在,我們的Spring配置文件先配置到這里,接下來,我們來創(chuàng)建我們的實體映射類User和他的實體映射文件User.hbm.xml:
在User類中,增加相關(guān)屬性,id,name,.age即可以,然后增加其set和get方法,這里就省略了。
然后我們創(chuàng)建其實體映射文件User.hbm.xml,要求和User類是在同一個包下:在這里注意一點,就是id的生成策略,在這里我們使用native,如果改為increment自增的話會出現(xiàn)一些問題,具體網(wǎng)上有解釋,可參考http://blog.sina.com.cn/s/blog_57554ed50100e3cu.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.zbvc.bean.User" table="users">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"/>
<property name="age"/>
</class>
</hibernate-mapping>
7.下面我們來完成第一個功能,增加一個用戶的操作(注:保證數(shù)據(jù)庫已經(jīng)有了我們需要使用數(shù)據(jù)庫oa),在寫增加操作之前我們需要明白一個流程,即SSH是如何運行的,他們的流程是什么?
首先客戶端提交需要保存的信息到filter,filter根據(jù)不同的需求轉(zhuǎn)發(fā)給不同的Action,Action調(diào)用業(yè)務(wù)邏輯層Service方法,Service層再調(diào)用持久層方法,持久層直接對數(shù)據(jù)庫進行操作,最后再一步步的返回相應(yīng)到Action,到客戶端。所以在寫我們的CRUD之前,我們還需要做一步就是建立我們的業(yè)務(wù)邏輯層和持久層還有Action表現(xiàn)層。
通過這個截圖圖,我們可以看到我們的相關(guān)類和接口已經(jīng)創(chuàng)建完成了,在這里我要說明的是,我們的Action可能會有好幾個,因為在這里我們只是寫一個demo,所以方便大家看,我們?yōu)楦髯缘墓δ芊謩e增加一個Action,另外,對于業(yè)務(wù)邏輯層,在這里它的功能和持久層一致,因為這是一個demo,沒有太多復(fù)雜的業(yè)務(wù),但為了養(yǎng)成良好的習(xí)慣我們還是強制的加上這個業(yè)務(wù)邏輯層。
(1)下面我們首先編寫DAO層的相關(guān)具體操作:
package cn.zbvc.dao;
import java.util.List;
import cn.zbvc.bean.User;
public interface UserDAO {
/**
* 保存用戶
* @param user
*/
public void saveUser(User user);
/**
* 刪除用戶
* @param id
*/
public void deleteUser(int id);
/**
* 根據(jù)id找到某個用戶
* @param id
*/
public User findUserById(int id);
/**
* 查詢所有的用戶
* @param user
* return List<User>
*/
public List<User> findAllUsers();
/**
* 更新用戶
* @param user
*/
public void updateUser(User user);
}
(2)具體實現(xiàn)類:
在具體實現(xiàn)類里我們需要注意,我們繼承了一個HibernateDaoSupport,這個類是Spring給我們提供的用于操作數(shù)據(jù)庫的類,使用非常簡單。具體代碼如下:
package cn.zbvc.dao.impl;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import cn.zbvc.bean.User;
import cn.zbvc.dao.UserDAO;
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
public void deleteUser(int id) {
User user = findUserById(id);
if(user != null){
this.getHibernateTemplate().delete(user);
}
}
@SuppressWarnings("unchecked")
public List<User> findAllUsers() {
String hql = "from User";
return (List<User>)this.getHibernateTemplate().find(hql);
}
public User findUserById(int id) {
return (User)this.getHibernateTemplate().get(User.class, id);
}
public void saveUser(User user) {
this.getHibernateTemplate().save(user);
}
public void updateUser(User user) {
this.getHibernateTemplate().update(user);
}
}
接下來拷貝相關(guān)代碼到業(yè)務(wù)邏輯層,注意:在業(yè)務(wù)邏輯層需要創(chuàng)建一個持久層的對象來調(diào)用持久層的方法,這個持久層對象我們使用Spring為我們創(chuàng)建,具體代碼如下:首先在業(yè)務(wù)層定義這樣一個持久層對象userDao.,同時我們Action還需要定義個業(yè)務(wù)邏輯層的對象,所以其創(chuàng)建也在配置文件中寫到。
<!-- 創(chuàng)建持久層Dao對象 依賴注入sessionFactory-->
<bean id="userDao" class="cn.zbvc.dao.impl.UserDAOImpl" scope="singleton">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 創(chuàng)建業(yè)務(wù)邏輯層Service對象 依賴注入其持久層對象屬性-->
<bean id="userService" class="cn.zbvc.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
再往下繼續(xù),我們需要編寫我們的Action了,第一個Action:SaveUserAction.java:保存用戶信息,以往的做法是添加這個用戶的屬性字段,實例化User對象,調(diào)用其set方法封裝信息到User對象中,然后調(diào)用相關(guān)方法。但是假設(shè)屬性字段比較多的時候這個方法不可取,現(xiàn)在我們使用模型驅(qū)動的方式獲取我們的表單信息,首先,我們編寫一個網(wǎng)頁,叫做save.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Save User</title>
</head>
<body>
<h1><font color="red">保存用戶</font></h1>
<s:form action="saveUser">
<!-- 注意name = 對象名.屬性名 -->
<s:textfield name="user.name" label="%{getText('name')}"></s:textfield>
<s:textfield name="user.age" label="%{getText('age')}"></s:textfield>
<s:submit value="提交"></s:submit>
</s:form>
</body>
</html>
然后我們需要配置Struts.xml相關(guān)信息:在這里我們看到我們的class是一個別名,也就是說我們對于Action的實例,也讓Spring托管了。另外當(dāng)返回結(jié)果為success的時候我們使其重定向為listUser.action,這個action的目的是為了顯示所有用戶信息的列表。具體代碼如下:
<!-- 保存用戶的Action -->
<action name="saveUser" class="saveUserAction">
<result name="success" type="redirect">listUser.action</result>
<result name="input">/save.jsp</result>
</action>
<!-- 顯示所有用戶的Action -->
<action name="listUser" class="listUserAction">
<result name="success">/listUser.jsp</result>
</action>
<!-- 創(chuàng)建控制層SaveUserAction的對象 依賴注入其業(yè)務(wù)層對象屬性 -->
<bean id="saveUserAction" class="cn.zbvc.action.user.SaveUserAction" scope="prototype">
<property name="service" ref="userService" />
</bean>
<!-- 創(chuàng)建ListUserAction的對象 依賴注入其業(yè)務(wù)邏輯層對象屬性-->
<bean id="listUserAction" class="cn.zbvc.action.user.ListUserAction" scope="prototype">
<property name="service" ref="userService" />
</bean>
SaveUserAction.java的具體代碼如下:
package cn.zbvc.action.user;
import cn.zbvc.bean.User;
import cn.zbvc.service.UserService;
import com.opensymphony.xwork2.ActionSupport;
/**
* 控制層Action
* @author 呂鵬
*/
public class SaveUserAction extends ActionSupport {
private User user;
private UserService service;//通過Spring創(chuàng)建業(yè)務(wù)層對象 使用set方法依賴注入
public void setService(UserService service) {
this.service = service;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
this.service.save(this.user);
return SUCCESS;
}
}
下面我們來進行一下測試,看我們能否保存數(shù)據(jù)到數(shù)據(jù)庫當(dāng)中,在這之前,請再次檢查一下相關(guān)配置,Struts.xml文件的配置,applicationContext.xml的配置等是否已經(jīng)都正確,然后加載服務(wù)器,啟動服務(wù)器,進入save.jsp頁面;
許多同學(xué)可能不知道listUser.jsp的頁面是如何顯示的。下面拷貝一下代碼:
<body>
<center>
<h1><font color="red">用戶列表</font></h1>
<table border="1" width="450">
<tr>
<td>序號</td>
<td>姓名</td>
<td>年齡</td>
<td>是否刪除</td>
<td>是否更新</td>
</tr>
<s:iterator value="listUser">
<tr>
<td><s:property value="id"/></td>
<td><s:property value="name"/></td>
<td><s:property value="age"/></td>
<td><a href='<s:url action="deleteUser.action"><s:param name="user.id" value="id"/></s:url>' onclick="return del()">刪除</a></td>
<td><a href='<s:url action="findUser.action"><s:param name="user.id" value="id"/></s:url>'>更新</a></td>
</tr>
</s:iterator>
</table>
</center>
</body>
從代碼中可以看到我們使用了Struts2的標(biāo)簽庫,其中迭代器的使用是比較方便的。剛才,我們完成了增加和查詢所有信息的操作,接著往下看,我們要對數(shù)據(jù)進行刪除和修改操作,先做刪除,刪除的話,我們要傳遞給DeleteAction一個id值,根據(jù)id值刪除我們在數(shù)據(jù)庫中的記錄,我們可以在Action里面寫這樣一個字段id,添加其set和get方法,在網(wǎng)頁上寫這樣的傳遞語句:(參考語句)
<td align="center"><a href="deleteUser.action?id=<s:property value="id"/>">刪除</a></td>
但是這樣的寫法有一個問題,沒有使用到我們之前的模型驅(qū)動,我們既然已經(jīng)定義了User的對象,我們使用Struts2的標(biāo)簽就可以簡化代碼為:
<td><a href='<s:url action="deleteUser.action"><s:param name="user.id" value="id"/></s:url>' onclick="return del()">刪除</a></td>
這樣寫的好處就是在Action中就沒必要再增加id這個字段和其方法了。
然后我們還需要寫相關(guān)的刪除和修改的Action,在struts.xml文件中進行配置,在applicationContext文件中進行Action的配置,代碼如下:
<!-- 刪除用戶的Action -->
<action name="deleteUser" class="deleteUserAction">
<result name="success" type="redirect">listUser.action</result>
</action>
<!-- 查詢用戶的Action -->
<action name="findUser" class="findUserAction">
<result name="success">/update.jsp</result>
</action>
<!-- 更新用戶的Action -->
<action name="updateUser" class="updateUserAction">
<result name="success" type="redirect">listUser.action</result>
<result name="input">update.jsp</result>
</action>
在這里,可能你有一個問題不明白,為什么還有一個findUser的Action,因為是這樣的,當(dāng)我們進行修改操作的時候,必要要傳遞一個id值,根據(jù)id值查到相關(guān)的信息,進入一個修改頁面,在修改頁面中需要顯示這個User的信息,所以這個過程需要用到findUser這個Action。
接下來是applicationContext.xml
<!-- 創(chuàng)建deleteUserAction的對象 依賴注入其業(yè)務(wù)邏輯層對象屬性-->
<bean id="deleteUserAction" class="cn.zbvc.action.user.DeleteUserAction" scope="prototype">
<property name="service" ref="userService" />
</bean>
<!-- 創(chuàng)建findUserAction的對象 依賴注入其業(yè)務(wù)邏輯層對象屬性-->
<bean id="findUserAction" class="cn.zbvc.action.user.FindUserAction" scope="prototype">
<property name="service" ref="userService" />
</bean>
<!-- 創(chuàng)建UpdateUserAction的對象 依賴注入其業(yè)務(wù)邏輯層對象屬性-->
<bean id="updateUserAction" class="cn.zbvc.action.user.UpdateUserAction" scope="prototype">
<property name="service" ref="userService" />
</bean>
在這些Action的配置中,你會發(fā)現(xiàn)多了一個參數(shù),即scope="prototype"。為什么要加這樣一個參數(shù),具體原因請瀏覽:http://blog.sina.com.cn/s/blog_5f12739d0100cre0.html
這樣,我們基本上就完成了CRUD的相關(guān)配置和代碼編寫,下面我們再次進行測試,看是否可以完成這些操作:
Index.jsp:
Save.jsp:
listUser.jsp:(非功能截圖)
Update.jsp:
顯示要修改的用戶
修改
修改成功
Delete.action:
這個對話框是使用js技術(shù)實現(xiàn)的,具體代碼如下:
<SCRIPT type="text/javascript">
function del()
{
var result = confirm("你確定刪除嗎?");
if(result)
{
return true;
}
else
{
return false;
}
}
</SCRIPT>
刪除成功(截圖略)
以上就是一個簡單的SSH整合的CRUD操作。
我們簡單的回顧一下:
(1)首先,我們分別使用導(dǎo)航配置了Hibernate和Spring的框架
(2)創(chuàng)建了實體映射類和實體映射文件User.hbm.xml
(3)然后我們導(dǎo)入了Struts2.2的相關(guān)包,配置了Struts.xml文件
(4)然后我們又配置了applicationContext.xml文件和web.xml文件
(5)最后編寫我們的Action,DAO,Service等
(6)最后編寫相關(guān)操作網(wǎng)頁等
講解當(dāng)中,我重點講解了一些重點,還希望大家回顧的時候好好看,我推薦的一些網(wǎng)站,也都是很重要的。
下面我們針對這個CRUD系統(tǒng),做一下擴展:
(1)國際化問題
在我們的表單里,默認語言為中文,所以顯示的label都是漢字,當(dāng)我們的默認語言設(shè)置為英文的情況下,顯示的依舊是中文,這樣是不健全的,所以我們需要使用Struts2國際化修改我們的jsp頁面,這里只做一個簡單的例子,將Save頁面的label國際化:
大家都知道,國際化要在struts.xml文件中加一句
<constant name="struts.custom.i18n.resources" value="globalMessages" />
這里我們使用另外一種方式,和這個道理是一樣的,我們建議資源文件:struts.properties,在文件中寫:
struts.custom.i18n.resources=globalMessages
然后我們再建立關(guān)于中文或者英文的相關(guān)資源文件:
以中文為例,要注意不可以保存中文字符,所以要利用一些工具進行操作:
id=\u5E8F\u53F7
name=\u59D3\u540D
age=\u5E74\u9F84
做完這些操作以后,我們需要在我們的頁面進行一下修改:
<s:form action="saveUser">
<!-- 注意label處調(diào)用的getText方法 -->
<s:textfield name="user.name" label="%{getText('name')}"></s:textfield>
<s:textfield name="user.age" label="%{getText('age')}"></s:textfield>
<s:submit value="提交"></s:submit>
</s:form>
然后我們把瀏覽器默認字符改成en 英文:
效果:
還有一個文件globalMessages.properties.這個文件的作用也是處理國際化問題,它還有一個作用是處理age的校驗,當(dāng)age字段接受的值為非數(shù)字的時候,將會出現(xiàn)文件的提示信息:
xwork.default.invalid.fieldvalue={0} \u683C\u5F0F\u4E0D\u6B63\u786E
國際化問題就講到這里。
(2)校驗問題
我們在保存用戶和修改修護的時候并沒有對其字段進行校驗,在這里我們擴展一下校驗:
大家所知道的校驗方式有這么兩三種,客戶端校驗和服務(wù)器的校驗,服務(wù)器的校驗又分重寫valdate方法,和校驗框架,對于客戶端校驗在這里就不寫了,對于validate方法這里也省略,我們來寫一下校驗框架,校驗框架就是字段校驗,代碼很簡單,拷貝一下:
<!-- 模型字段校驗方式 -->
<validators>
<field name="user.name">
<field-validator type="requiredstring">
<message>姓名不能為空</message>
</field-validator>
</field>
<field name="user.age">
<field-validator type="required">
<message>required age</message>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>年齡應(yīng)該保持在 ${min} 到 ${max}</message>
</field-validator>
</field>
</validators>
我們講這種校驗方式叫做 模型字段校驗方式,使用起來也比較容易理解,下面我們介紹另外一種校驗方式,visitor方式:
<!--visitor校驗方式-->
<validators>
<!-- 要校驗的屬性 -->
<field name="user">
<!-- 校驗類型 -->
<field-validator type="visitor">
<!-- 上下文:具體的檢驗文件名字在這里指定 -->
<param name="context">user</param>
<!-- 附加前綴 比如:'用戶的' -->
<param name="appendPrefix">true</param>
<!-- 附加前綴內(nèi)容 -->
<message>用戶的 </message>
</field-validator>
</field>
</validators>
我們發(fā)現(xiàn)我們的代碼明顯少了很多,看具體代碼,都有注釋,也容易理解。既然我們說使用這種校驗方式,可是我們并沒有看到具體的校驗代碼,原因是因為我們把校驗的代碼放到了別的地方,我們應(yīng)該放在什么地方呢?Action是不斷變化的,我們放在User對象所在的包下就可以了:
首先我們在User類所在包下建立這樣一個文件User-user-validation.xml這個文件的命名是有一定講究的,第一個User是要校驗的類,第二個user是這個文件的真實名字,這個名字在前面的配置文件中出現(xiàn)過。。。里面的具體代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="name">
<field-validator type="requiredstring">
<message>姓名不能為空</message>
</field-validator>
</field>
<field name="age">
<field-validator type="required">
<message>required age</message>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">150</param>
<message>年齡應(yīng)該保持在 ${min} 到 ${max}</message>
</field-validator>
</field>
</validators>
我們看一下效果:當(dāng)什么都不輸入的時候:
好,以上就是對這樣一個SSH整合的CRUD的擴展,這節(jié)就到這里,接下來,我還會陸續(xù)的整理一些關(guān)于框架整合的案例,以此鞏固框架的整合,慢慢的提升能力。下節(jié)課,我們在本節(jié)課的基礎(chǔ)上再次的擴展,內(nèi)容如下:
當(dāng)我們查看數(shù)據(jù)庫的信息的時候,數(shù)據(jù)庫過大的情況下,我們需要采用分頁,分頁機制在開發(fā)中是一件繁瑣而又復(fù)雜的事。下節(jié)課,我們來整理這樣一個分頁機制,幫助大家理解分頁功能的實現(xiàn)。