国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Spring、Hibernate、Struts1整合的方式
http://zxmzfbdc.javaeye.com/blog/258946

【原創(chuàng)】Spring、Hibernate、Struts1整合的方式
  完整的例子源碼已經(jīng)作為附件上傳,為了減小體積,沒有包含用到的jar文件,請讀者自己下載,不便處還請見諒。
  9.1 模型概述
  正如我們所知,Struts是一個單純的web框架,因此對于其他方面的操作無能為力,例如對數(shù)據(jù)庫的操作。此外它也不能管理對象之間的依賴關(guān)系,因此需要和持久化框架和IoC框架結(jié)合,才能構(gòu)建一個完整健壯的系統(tǒng)。本節(jié)分析Struts+Spring+Hibernate結(jié)合的必要性。
  9.1.1 三種模型結(jié)合的必要性
  對于從事web開發(fā)的人來說,使用Struts可以大大簡化開發(fā)過程,對于直接使用Servlet+JSP來說,它提供了優(yōu)秀的封裝機制,使得用戶可以嚴(yán)格按照MVC架構(gòu)來開發(fā)應(yīng)用。想想我們沒有使用web框架之前,是怎樣的混亂狀態(tài),需要自己將數(shù)據(jù)從請求中取出來,然后組裝起來,在數(shù)據(jù)很多的情況下,這簡直是一個噩夢。驗證代碼散落在各處,維護它們同樣是一件累人的活。為了處理不同的請求,可能需要寫很多的Servlet,且不說容器的負擔(dān)問題,單單是web.xml文件就變得分外的臃腫,最后可能變成一個難以維護的龐然大物。這是我在實際開發(fā)中遇到過的真實情況。盡管使用Struts,在早期也會遇到配置文件(struts-config.xml)膨脹的問題,但后來的Struts通過模塊化很好的解決了這個問題。
  關(guān)于驗證,需要多說一些,事實上,Struts的驗證并不像后來的一些web框架而言,如Webwork、Spring MVC,是可插拔的,相反,它被包含在ActionForm中,這是一種耦合性較強的設(shè)計。form負擔(dān)了的太多的責(zé)任,使得重用它變得困難,比如在業(yè)務(wù)層和持久層,另外,form是Struts框架的一部分,出于降低耦合性的考慮,也不能在業(yè)務(wù)層和持久層中出現(xiàn)。它之后的一些框架都很好的解決了這個問題:使用一個普通的pojo,僅僅用于封裝數(shù)據(jù),不包含任何的邏輯。但是,Struts是一個可擴展的框架,它的任何一部份都是可以替換的。我們可以通過它提供的插件機制,來提供自己的功能,例如通常情況下,Spring和Struts的整合的一種方式,就是通過插件實現(xiàn)的。通過插件,我們也可以提供可插拔的驗證功能。
  Struts是一個經(jīng)歷了無數(shù)項目考驗的框架,有著為數(shù)最為龐大的社群,有著成熟的經(jīng)驗可供參考,所以在項目中使用Struts風(fēng)險很小。而且,Struts比較容易上手,因此學(xué)習(xí)成本也相對較小。
  正如我們前面所說的,Struts是一個純粹的web框架,不涉及業(yè)務(wù)層和持久層的處理,因此,對于其他層需要借助于其他的框架。比如,在持久層使用 Hibernate。
  數(shù)據(jù)庫操作是一個很復(fù)雜的問題,盡管在Java中,JDBC進行了很好的抽象,但是用戶需要直接操作SQL。這里也存在一個數(shù)據(jù)組裝的問題,實際開發(fā)中直接從ResultSet中取出數(shù)據(jù),然后放入一個model中,是很常見的方式。冗長的set操作令人厭煩。我們在實際開發(fā)中,都是將數(shù)據(jù)存放到model中,然后操作model,在這個意義上說,model和數(shù)據(jù)庫之間有著某種內(nèi)在的關(guān)系。怎樣映射這種關(guān)系,正是ORM所要做的。ORM不僅僅要映射對象的屬性和數(shù)據(jù)庫表的字段間的關(guān)系,還要把表之間的關(guān)系映射為對象之間的關(guān)系,從而把對數(shù)據(jù)庫表的操作,完全轉(zhuǎn)為對對象的操作。這種處理方式,更為程序員所熟悉,而且通過工具,我們也很容易保持表關(guān)系和對象關(guān)系的同步。Hibernate正是這樣一個強大的ORM工具,除了通常的O-R映射,還提供了其他的廣受歡迎的功能,比如臟數(shù)據(jù)檢查、延遲加載等。這些,我們在前面的章節(jié)中,已經(jīng)做過介紹。Hibernate在實際開發(fā)中獲得了廣泛的應(yīng)用,成為事實上的標(biāo)準(zhǔn)。所以,我們在開發(fā)中,持久層實現(xiàn),可以選擇Hibernate。
  Struts同樣也缺少IoC和AOP功能,因此存在一定的耦合,例如,在Action調(diào)用業(yè)務(wù)對象的時候,需要new一個實例,這是很常見的情況。當(dāng)然,我們可以使用工廠模式消除這種情況,但是又需要引入工廠類。使用Spring可以有效地消除這種耦合。我們在上一章中,介紹的Spring和Struts整合的方式中,可我們在Action中通過Spring的ApplicationContext獲取對象,但是這樣Action中又嵌入了Spring的代碼。整合的第三種方式,通過Struts的plug-in機制,將Action交由Spring托管,這樣,我們就可以在Action中使用依賴注入,完全消除了這種耦合。除此之外,我們還可以使用Spring的AOP機制。通過整合,我們可以充分利用各個框架的優(yōu)勢,從而達到構(gòu)建完美的應(yīng)用的目標(biāo)。
  9.2 模型特征
  我們分析了三種框架結(jié)合的必要性,現(xiàn)在我們分析一下使用三個框架的模型特性。
  9.2.1 模型的構(gòu)成特點
  在Spring+Hibernate+Struts模型中,Hibernate負責(zé)持久化操作,Struts負責(zé)web操作,兩者之間完全獨立。Spring在這個模型中的地位很特殊,它提供對對象的管理,而不管這個對象是處在哪一層,完成哪些任務(wù)。Spring為用戶設(shè)置對象間的依賴關(guān)系,并且通過AOP提供了統(tǒng)一的方式,處理橫向的需求,這些需求通常很難使用OO實現(xiàn),比如權(quán)限驗證。這樣,Spring就涉及到廣泛的領(lǐng)域,而不管它處在哪一層。或者說,Spring是一個更為基礎(chǔ)的框架,而不像Struts和Hibernate專注于各自的領(lǐng)域。
  現(xiàn)在已經(jīng)清楚了Spring、Hibernate、Struts的作用,現(xiàn)在從分層的角度,分析一下這個模型。
  業(yè)務(wù)層,處理實際的邏輯操作,這一部分是由用戶獨立實現(xiàn)的,擁有最大的靈活性。有些時候,持久層和業(yè)務(wù)層是混合在一起的,但是數(shù)據(jù)庫一旦設(shè)計完成,就很少修改,所有擁有相當(dāng)?shù)姆€(wěn)定性,所以持久層也擁有相當(dāng)?shù)姆€(wěn)定性,因此可以將它們獨立出來。還有一個原因,持久化操作,很多時候很復(fù)雜,特別是涉及到事物的時候,因此,維護一個穩(wěn)定的持久層,有利于分工,也減少了維護的成本。Hibernate的出現(xiàn),使得持久化操作不再像以前那么復(fù)雜繁瑣,所以也有將這兩層合并的做法。我們下面給出的例子,會看到很多時候業(yè)務(wù)層僅僅是將請求委托給持久層,本身什么也不做。但我認為,維護一個獨立的業(yè)務(wù)層,還是有好處的,至少在將來切換持久化實現(xiàn)的時候,比如用JDBC替換Hibernate,業(yè)務(wù)層就不用作任何的改動,雖然這種情況很少發(fā)生。
  持久層,我們可以直接使用Hibernate API,更好的方式是使用Spring的Hibernate封裝。Spring提供了對Hibernate的良好封裝,這樣我們在持久化操作中,可以使用Spring提供的封裝,簡化持久化的操作。Hibernate的Session是很昂貴的資源,因此,每個DAO(這里指持久層的類)方法,單獨使用一個Session是一種浪費,使用Spring的封裝,就可以使用統(tǒng)一的方式使用Session。通過使用Spring托管的Session,我們實現(xiàn)了OpenSessionInView模式,即在每一個請求中使用一個Session。當(dāng)然我們可以提供自己的OpenSessionInView實現(xiàn),最簡單的就是實現(xiàn)一個Filter。事實上Spring提供的其中一種實現(xiàn)就是通過這種方式實現(xiàn)的。在Spring托管的環(huán)境下,我們就可以實現(xiàn)Hibernate的聲明式管理。使用Spring封裝的一個好處就是對異常的處理,Spring可以給出很明確的異常信息,不像JDBC統(tǒng)一拋出SQLException,Hibernate拋出HibernateException。Spring還提供了異常轉(zhuǎn)換的功能,用戶可以在配置文件中聲明轉(zhuǎn)換成什么樣的異常。
  web層,就是Struts的責(zé)任了,這里通常不會涉及到Hibernate和Spring,我們僅僅是由Spring管理依賴對象的注入。但是,很多時候web請求需要一些橫向的需求,比如上面提到的權(quán)限管理,一個更常見的情況是用戶登錄和注冊。當(dāng)然我們可以使用Filter實現(xiàn),也可以寫一個頂層的Action,統(tǒng)一處理這些請求,需要處理這些請求的Action繼承它即可。但是這是一種硬編碼的實現(xiàn),不能通過配置改變,因此缺少靈活性。用戶是否登錄的判斷也是一個典型的橫切應(yīng)用,因此可以通過AOP來實現(xiàn)。我們下面的例子,會給出一個使用攔截器判斷用戶是否登錄的實現(xiàn)。為了使用攔截器,我們這里給出了Spring和Struts整合的第四種方式,涉及到了SpringMVC的內(nèi)容。相對來說,SpringMVC在設(shè)計上更加倚重IoC和AOP,也提供了更為開放的方式,因此更為強大,但是卻過于復(fù)雜。但是相對于它提供的豐富特性,這些復(fù)雜性是可以克服的,因此在實際開發(fā)中,可以考慮用SpringMVC實現(xiàn)web層,即用它替換Struts。
  9.2.2 實現(xiàn)模型的目的
  使用Spring+Hibernate+Struts模型的目的,實際上面已經(jīng)涉及到了,這些框架的優(yōu)點是使用它們的一個重要原因。還有一些可能更重要的原因,總結(jié)如下:
  去耦合 這是一個老生常談的話題了。去耦合是如此的重要,以至于人們要將這方面的經(jīng)驗總結(jié)成設(shè)計模式。Spring通過IoC,實現(xiàn)了去耦合,這樣用戶可以隨時替換現(xiàn)在的實現(xiàn),而不用修改源碼。這正是軟件開發(fā)中開-閉原則的要求。Spring倡導(dǎo)面向接口編程,這是最為推崇的最佳實踐之一,繼承僅僅作為內(nèi)部實現(xiàn)的一個手段。面向接口編程,不僅僅是提供了更好的抽象,實際上也更有利于去耦合。
  擴展的需要 Struts、Spring甚至Hibernate都提供了良好的擴展功能,Struts通過插件機制,可以很方便的添加功能。Spring對Bean的管理也提供了擴展,例如用戶可以提供自己的作用域。Hibernate用戶可以定制自己的持久化策略。
  維護的需要 這些框架都很容易維護,它們都很好的實現(xiàn)了開-閉原則,因此需要替換功能的時候,只需簡單的修改配置文件。它們提供的一些公用功能,也能通過配置的方式提供,比如Spring的聲明式事務(wù)。因此維護成本大大降低。
  還有一個原因,由于它們都有龐大的社區(qū)支持,因此尋找技術(shù)支持很容易。由于它們很流行,因此招一個開發(fā)人員也很容易。    
  9.3 Hibernate+Spring+Struts模型應(yīng)用分析
  通過上面的學(xué)習(xí),我們對三者結(jié)合的模型有了一個概念性的理解,現(xiàn)在我們通過一個具體的例子,演示怎樣將它們整合在一起。
  9.3.1 應(yīng)用事例
  我們考慮一個購物車的例子,相信讀者或多或少都接觸過這方面的例子。為了簡單起見,我們不考慮庫存的問題,商品的信息完全由用戶填寫,包括商品名稱、商品介紹、商品價格、購買數(shù)量。填寫完商品信息,會被暫時放入購物車內(nèi),每個購物車抽象成一個訂單。當(dāng)用戶確認購買的商品后,就可以提交購物車,從而這些信息被存入數(shù)據(jù)庫,購物車清空。在做這些操作之前,用戶首先需要登錄,如果用戶沒有注冊,可以選擇注冊。用戶不僅可以購買商品,還可以查看已經(jīng)提交的訂單的詳細信息。一個用戶可以有多個訂單,一個訂單只能屬于一個用戶。同理,一個訂單可以包含多個商品,而一個商品只能屬于一個訂單。用戶的姓名是唯一的,因為這是確認用戶的唯一憑證。這就是全部的需求。
  9.3.2 事例分析
  好,現(xiàn)在我們開始構(gòu)建整個應(yīng)用。應(yīng)用用到的類庫如圖9-1所示:

圖9-1 應(yīng)用用到的jar包
  首先,我們需要建立所需的數(shù)據(jù)庫表,我們用到的表有三個,每個表都有一個用于標(biāo)識的id,這三個表分別是:

•tb_user——用戶表,用來存放用戶信息,包括用戶名和密碼;
•tb_order——訂單表,用來存放訂單信息,包括訂單描述、生成時間、用戶id;
•tb_item——商品表,用來存放商品信息,包括商品名稱、商品描述、商品價格、購買數(shù)量、定單id。

  我用的數(shù)據(jù)庫是Oracle9i,生成三個表用到的SQL如下:
  
Sql代碼
1./*商品表*/  
2.create table tb_item (  
3.    id number(10,0) not null,  
4.    orderid number(10,0) not null,      /*訂單id*/  
5.    name varchar2(20 char) not null,    /*商品名稱*/  
6.    description varchar2(800 char),     /*商品描述*/  
7.    price number(18,2),              /*商品價格*/  
8.    count number(10,0),              /*購買數(shù)量*/  
9.    primary key (id)  
10.)  
11. 
12./*訂單表*/  
13.create table tb_order (  
14.    id number(10,0) not null,  
15.    userid number(10,0) not null,      /*用戶id*/  
16.    description varchar2(800 char),    /*訂單描述*/  
17.    createTime timestamp,           /*生成時間*/  
18.    primary key (id)  
19.)  
20. 
21./*用戶表*/  
22.create table tb_user (  
23.    id number(10,0) not null,  
24.    name varchar2(20 char) not null,        /*用戶名*/  
25.    password varchar2(20 char) not null,     /*密碼*/  
26.    primary key (id)  
27.)  
28. 
29.alter table tb_item   
30.    add constraint FKA4F9FA443A36B48F   
31.    foreign key (orderid)   
32.    references tb_order  
33. 
34.alter table tb_order   
35.    add constraint FKFA98EE3D6705FE99   
36.    foreign key (userid)   
37.    references zxm.tb_user  
38. 
39.create sequence hibernate_sequence 
    /*商品表*/
    create table tb_item (
        id number(10,0) not null,
        orderid number(10,0) not null,      /*訂單id*/
        name varchar2(20 char) not null,    /*商品名稱*/
        description varchar2(800 char),     /*商品描述*/
        price number(18,2),              /*商品價格*/
        count number(10,0),              /*購買數(shù)量*/
        primary key (id)
    )

    /*訂單表*/
    create table tb_order (
        id number(10,0) not null,
        userid number(10,0) not null,      /*用戶id*/
        description varchar2(800 char),    /*訂單描述*/
        createTime timestamp,           /*生成時間*/
        primary key (id)
    )

    /*用戶表*/
    create table tb_user (
        id number(10,0) not null,
        name varchar2(20 char) not null,        /*用戶名*/
        password varchar2(20 char) not null,     /*密碼*/
        primary key (id)
    )

    alter table tb_item
        add constraint FKA4F9FA443A36B48F
        foreign key (orderid)
        references tb_order

    alter table tb_order
        add constraint FKFA98EE3D6705FE99
        foreign key (userid)
        references zxm.tb_user

    create sequence hibernate_sequence
  接下來,我們生成pojo和相關(guān)的hibernate映射文件,這可以通過hibernate-tools實現(xiàn),也可以通過Middlegen實現(xiàn)。pojo對應(yīng)的名字分別是User、Order和Item,映射文件和pojo同名。注意包名的命名,通過包,我們可以將類進行分組,便于管理。我們在開發(fā)中,應(yīng)該重視包的管理,至少在一個應(yīng)用中,應(yīng)該有統(tǒng)一的命名規(guī)范。這里使用的命名習(xí)慣和放置的文件是這樣的:

•cn.zxm.order.pojo——pojo和相關(guān)的映射文件;
•cn.zxm.order.dao——持久化接口;
•cn.zxm.order.dao.impl——持久化接口的實現(xiàn)類;
•cn.zxm.order.service——業(yè)務(wù)接口;
•cn.zxm.order.service.impl——業(yè)務(wù)接口的實現(xiàn)類;
•cn.zxm.order.form——應(yīng)用用到的ActionForm;
•cn.zxm.order.action——應(yīng)用用到的Action;
•cn.zxm.order.util——應(yīng)用用到的工具類。

  這里我們只列出pojo的源碼,省略映射文件,其他的接口和類會在后面列出:
User.java:

Java代碼
1.public class User implements java.io.Serializable {  
2.    private Integer id;  
3.    private String name;  
4.    private String password;  
5.    private Set<Order> orders = new HashSet<Order>(0);  
6. 
7.……對應(yīng)的setter和getter方法……  
8.} 
public class User implements java.io.Serializable {
private Integer id;
private String name;
private String password;
private Set<Order> orders = new HashSet<Order>(0);

……對應(yīng)的setter和getter方法……
}
Order.java:

Java代碼
1.public class Order implements java.io.Serializable {  
2.    private Integer id;  
3.    private User user;  
4.    private String description;  
5.    private Date createTime;  
6.    private Set<Item> items = new HashSet<Item>(0);  
7. 
8.……對應(yīng)的setter和getter方法……  
9.} 
public class Order implements java.io.Serializable {
private Integer id;
private User user;
private String description;
private Date createTime;
private Set<Item> items = new HashSet<Item>(0);

……對應(yīng)的setter和getter方法……
}
Item.java:

Java代碼
1.public class Item implements java.io.Serializable {  
2.    private Integer id;  
3.    private Order order;  
4.    private String name;  
5.    private String description;  
6.    private BigDecimal price;  
7.    private Integer count;  
8. 
9.……對應(yīng)的setter和getter方法……  
10.} 
public class Item implements java.io.Serializable {
private Integer id;
private Order order;
private String name;
private String description;
private BigDecimal price;
private Integer count;

……對應(yīng)的setter和getter方法……
}

  第三步,構(gòu)建持久化接口和它們的實現(xiàn)。開始構(gòu)建時,我們可能不知道需要哪些方法,沒有關(guān)系,我們從最小需求來考慮,只定義肯定用到的方法即可,至于應(yīng)用中需要新的方法,可以通過重構(gòu)添加,現(xiàn)在的IDE很多都提供了很好的重構(gòu)功能。那么重構(gòu)時是先從接口開始,還是從實現(xiàn)開始?一般來說,從接口開始保證實現(xiàn)必須包含這個方法,但是從類開始,我們可能會忘記將方法上推到接口。不過,這個問題不大,因為我們實際開發(fā)時用到的是接口,所以,這個不是問題。我的建議是從實現(xiàn)開始重構(gòu)。
  針對用戶的操作,我們需要根據(jù)主鍵獲取用戶信息。由于要處理用戶注冊,所以需要保存用戶信息。要處理登錄,所以需要根據(jù)用戶名獲取用戶信息。這就是需要用到的三個方法,借口定義如下:

Java代碼
1.public interface UserDAO {  
2.    /** 
3.     * 保存用戶 
4.     * @param user 
5.     */ 
6.    void save(User user);  
7.      
8.    /** 
9.     * 根據(jù)用戶id獲取用戶信息  
10.     * @param id 
11.     * @return 
12.     */ 
13.    User getUser(int id);  
14.      
15.    /** 
16.     * 根據(jù)用戶名獲取用戶信息 
17.     * @param name 
18.     * @return 
19.     */ 
20.    User getUserByName(String name);  
21.} 
public interface UserDAO {
/**
* 保存用戶
* @param user
*/
void save(User user);

/**
* 根據(jù)用戶id獲取用戶信息
* @param id
* @return
*/
User getUser(int id);

/**
* 根據(jù)用戶名獲取用戶信息
* @param name
* @return
*/
User getUserByName(String name);
}

  對應(yīng)的實現(xiàn)我們用到了Spring的HibernateTemplate類,這個類封裝了對于Hibernate的通用操作。實現(xiàn)如下:
UserDAOImpl:

Java代碼
1.public class UserDAOImpl implements UserDAO {  
2.        protected HibernateTemplate hibernate;  
3. 
4.    public void setHibernate(HibernateTemplate hibernate) {  
5.        this.hibernate = hibernate;  
6.    }  
7. 
8.    public User getUser(int id) {  
9.        return (User)hibernate.load(User.class, id);  
10.    }  
11. 
12.    public User getUserByName(String name) {  
13.        String hql = "from User where name=?";  
14.        User user = null;  
15.        //使用iterate方法,第二個參數(shù)可以是一個數(shù)組,用來給hql中的參數(shù)賦值  
16.        Iterator<User> iterator = hibernate.iterate(hql, name);  
17.        //獲取用戶信息,沒有將返回null  
18.        if(iterator.hasNext()){  
19.            user = iterator.next();  
20.        }  
21.        return user;  
22.    }  
23. 
24.    public void save(User user) {  
25.        hibernate.saveOrUpdate(user);  
26.    }  
27.} 
public class UserDAOImpl implements UserDAO {
protected HibernateTemplate hibernate;

public void setHibernate(HibernateTemplate hibernate) {
this.hibernate = hibernate;
}

public User getUser(int id) {
return (User)hibernate.load(User.class, id);
}

public User getUserByName(String name) {
String hql = "from User where name=?";
User user = null;
//使用iterate方法,第二個參數(shù)可以是一個數(shù)組,用來給hql中的參數(shù)賦值
Iterator<User> iterator = hibernate.iterate(hql, name);
//獲取用戶信息,沒有將返回null
if(iterator.hasNext()){
user = iterator.next();
}
return user;
}

public void save(User user) {
hibernate.saveOrUpdate(user);
}
}

  由于HibernateTemplate在其他的DAO實現(xiàn)中也要用到,因此我們可以把它放到一個超類中,這樣所有的DAO實現(xiàn)先就可以通過繼承這個超類,而不在需要自己聲明HibernateTemplate。超類命名為BaseDAO,代碼如下:

Java代碼
1.public class BaseDAO {  
2.    protected HibernateTemplate hibernate;  
3. 
4.    public BaseDAO() {  
5.            super();  
6.    }  
7. 
8.    public void setHibernate(HibernateTemplate hibernate) {  
9.        this.hibernate = hibernate;  
10.    }  
11.} 
public class BaseDAO {
  protected HibernateTemplate hibernate;

  public BaseDAO() {
     super();
}

public void setHibernate(HibernateTemplate hibernate) {
this.hibernate = hibernate;
}
}

  修改UserDAOImpl,使他繼承BaseDAO,代碼如下:

Java代碼
1.public class UserDAOImpl extends BaseDAO implements UserDAO {  
2.    public User getUser(int id) {  
3.        ……  
4.    }  
5. 
6.    public User getUserByName(String name) {  
7.        ……  
8.    }  
9. 
10.    public void save(User user) {  
11.        ……  
12.    }  
13.} 
public class UserDAOImpl extends BaseDAO implements UserDAO {
public User getUser(int id) {
……
}

public User getUserByName(String name) {
……
}

public void save(User user) {
……
}
}
  訂單操作同樣需要保存操作,可能需要刪除操作,因為要查看訂單,顯然需要一個查詢方法,為了簡單,這里不考慮修改操作(由于Hibernate有臟數(shù)據(jù)檢查功能,實際上,通過查詢方法,我們也可以實現(xiàn)修改操作)。代碼如下:

Java代碼
1.public interface OrderDAO {  
2.    /** 
3.     * 保存訂單 
4.     * @param order 
5.     */ 
6.    void save(Order order);  
7.      
8.    /** 
9.     * 根據(jù)訂單id獲取訂單信息 
10.     * @param id 
11.     * @return 
12.     */ 
13.    Order getOrder(int id);  
14.      
15.    /** 
16.     * 刪除訂單 
17.     * @param order 
18.     */ 
19.    void delete(Order order);  
20.} 
public interface OrderDAO {
/**
* 保存訂單
* @param order
*/
void save(Order order);

/**
* 根據(jù)訂單id獲取訂單信息
* @param id
* @return
*/
Order getOrder(int id);

/**
* 刪除訂單
* @param order
*/
void delete(Order order);
}

  OrderDAO的實現(xiàn)代碼如下:

Java代碼
1.public class OrderDAOImpl extends BaseDAO implements OrderDAO {  
2.        public Order getOrder(int id) {  
3.        return (Order)hibernate.load(Order.class, id);  
4.        }  
5. 
6.        public void save(Order order) {  
7.            hibernate.save(order);  
8.        }  
9. 
10.    public void delete(Order order) {  
11.            hibernate.delete(order);  
12.    }  
13.} 
public class OrderDAOImpl extends BaseDAO implements OrderDAO {
public Order getOrder(int id) {
return (Order)hibernate.load(Order.class, id);
}

public void save(Order order) {
hibernate.save(order);
}

public void delete(Order order) {
hibernate.delete(order);
}
}

  商品的操作,我們是直接放在session中,只有提交訂單時才會涉及到保存操作,這里我們使用Hibernate的級聯(lián)保存,因此不涉及單獨操作Item的情況,ItemDAO在這個事例中不需要,這里省略。讀者可以自己完善這個應(yīng)用,比如刪除訂單和查看單個商品信息等。
持久層邏輯完成了,現(xiàn)在我們考慮一下邏輯層的實現(xiàn)。
  用戶操作和DAO的操作相似,只不過這里只有業(yè)務(wù)處理,不會涉及數(shù)據(jù)存取的操作,代碼如下:

Java代碼
1.public interface UserService {  
2.    /** 
3.     * 保存用戶 
4.     * @param user 
5.     */ 
6.    void save(User user);  
7. 
8.    /** 
9.     * 根據(jù)用戶id獲取用戶信息 
10.     * @param id 
11.     * @return 
12.     */ 
13.    User getUser(int id);  
14. 
15.    /** 
16.     * 根據(jù)傳入的用戶數(shù)據(jù)獲取完整的用戶信息 
17.     * @param user 
18.     * @return 
19.     */ 
20.    User getUser(User user);  
21.} 
public interface UserService {
/**
* 保存用戶
* @param user
*/
void save(User user);

/**
* 根據(jù)用戶id獲取用戶信息
* @param id
* @return
*/
User getUser(int id);

/**
* 根據(jù)傳入的用戶數(shù)據(jù)獲取完整的用戶信息
* @param user
* @return
*/
User getUser(User user);
}

  對應(yīng)的實現(xiàn)如下:

Java代碼
1.public class UserServiceImpl implements UserService {  
2.    private final Log log = LogFactory.getLog(UserServiceImpl.class);  
3.    private UserDAO userDAO;  
4.      
5.    public void setUserDAO(UserDAO userDAO) {  
6.        this.userDAO = userDAO;  
7.    }  
8.      
9.    public User getUser(User user) {  
10.        log.debug("驗證用戶");  
11.        return userDAO.getUserByName(user.getName());  
12.    }  
13. 
14.    public User getUser(int id) {  
15.        return userDAO.getUser(id);  
16.    }  
17. 
18.    /** 
19.     * 這里使用了事務(wù)標(biāo)注,這樣可以使用聲明式事務(wù) 
20.     * 如果用戶名為空,將不會保存 
21.     */ 
22.    @Transactional 
23.    public void save(User user) {  
24.        log.debug("保存用戶");  
25.        if(userDAO.getUserByName(user.getName())!=null)  
26.            return;  
27.        userDAO.save(user);  
28.    }  
29.} 
public class UserServiceImpl implements UserService {
private final Log log = LogFactory.getLog(UserServiceImpl.class);
private UserDAO userDAO;

public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}

public User getUser(User user) {
log.debug("驗證用戶");
return userDAO.getUserByName(user.getName());
}

public User getUser(int id) {
return userDAO.getUser(id);
}

/**
* 這里使用了事務(wù)標(biāo)注,這樣可以使用聲明式事務(wù)
* 如果用戶名為空,將不會保存
*/
@Transactional
public void save(User user) {
log.debug("保存用戶");
if(userDAO.getUserByName(user.getName())!=null)
return;
userDAO.save(user);
}
}

  訂單的處理,我們需要一個獲取訂單信息的方法,還需要一個保存訂單的方法,接口代碼如下:

Java代碼
1.public interface OrderService {  
2.    /** 
3.     * 獲取訂單詳細信息 
4.     * @param id 
5.     * @return 
6.     */ 
7.    Order getOrder(int id);  
8.      
9.    /** 
10.     * 保存訂單 
11.     * @param order 
12.     */ 
13.    void save(Order order);  
14.} 
public interface OrderService {
/**
* 獲取訂單詳細信息
* @param id
* @return
*/
Order getOrder(int id);

/**
* 保存訂單
* @param order
*/
void save(Order order);
}

  對應(yīng)的實現(xiàn)如下:

Java代碼
1.public class OrderServiceImpl implements OrderService {  
2.    private OrderDAO orderDAO;  
3.      
4.    public void setOrderDAO(OrderDAO orderDAO) {  
5.        this.orderDAO = orderDAO;  
6.    }  
7.      
8.    public Order getOrder(int id) {  
9.        return orderDAO.getOrder(id);  
10.    }  
11. 
12.    /** 
13.     * 保存訂單,我們在這里給訂單設(shè)置了生成時間 
14.     */ 
15.    @Transactional 
16.    public void save(Order order) {  
17.        order.setCreateTime(new Timestamp(System.currentTimeMillis()));  
18.        orderDAO.save(order);  
19.    }  
20.} 
public class OrderServiceImpl implements OrderService {
private OrderDAO orderDAO;

public void setOrderDAO(OrderDAO orderDAO) {
this.orderDAO = orderDAO;
}

public Order getOrder(int id) {
return orderDAO.getOrder(id);
}

/**
* 保存訂單,我們在這里給訂單設(shè)置了生成時間
*/
@Transactional
public void save(Order order) {
order.setCreateTime(new Timestamp(System.currentTimeMillis()));
orderDAO.save(order);
}
}

  我們的購物車是通過HttpSession實現(xiàn)的,因此我們在這里不是定義一個Service,還是通過一個工具類,實現(xiàn)操作購物車的功能。這里購物車中保存的是一個尚未提交的訂單。由于需要向訂單內(nèi)保存商品,我們在Order中增加一個方法,代碼如下:

Java代碼
1.      /** 
2. * 添加商品,注意我們手動為商品添加了訂單關(guān)聯(lián), 
3. * 這是為了使用Hibernate的級聯(lián)保存 
4. * @param item 
5. */ 
6.public void addItem(Item item){  
7.    item.setOrder(this);  
8.    items.add(item);  
9.} 
       /**
* 添加商品,注意我們手動為商品添加了訂單關(guān)聯(lián),
* 這是為了使用Hibernate的級聯(lián)保存
* @param item
*/
public void addItem(Item item){
item.setOrder(this);
items.add(item);
}

  工具類的代碼如下:

Java代碼
1.public final class OrderUtils {  
2.    /** 
3.     * 將商品放入購物車 
4.     * @param request 
5.     * @param item 
6.     */ 
7.    public static void saveItem(HttpServletRequest request, Item item) {  
8.        HttpSession session = request.getSession();  
9.        User user = (User)session.getAttribute("user");  
10.        Order order = getOrder(request);  
11.        order.addItem(item);  
12.        session.setAttribute(user.getName(), order);  
13.    }  
14. 
15.    /** 
16.     * 獲取購物車信息 
17.     * @param request 
18.     * @return 
19.     */ 
20. 
21.    public static Order getOrder(HttpServletRequest request) {  
22.        HttpSession session = request.getSession();  
23.        User user = (User)session.getAttribute("user");  
24.        Order order = (Order)session.getAttribute(user.getName());  
25.    //如果session沒有Order對象,那么就是實例化一個  
26.        if(order==null) {  
27.            order = new Order();  
28.        }  
29.        return order;  
30.    }  
31.      
32.    /** 
33.     * 清空購物車 
34.     * @param request 
35.     */ 
36.    public static void clearCart(HttpServletRequest request){  
37.        HttpSession session = request.getSession();  
38.        User user = (User)session.getAttribute("user");  
39.        session.removeAttribute(user.getName());  
40.    }  
41.} 
public final class OrderUtils {
/**
* 將商品放入購物車
* @param request
* @param item
*/
public static void saveItem(HttpServletRequest request, Item item) {
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");
Order order = getOrder(request);
order.addItem(item);
session.setAttribute(user.getName(), order);
}

/**
* 獲取購物車信息
* @param request
* @return
*/

public static Order getOrder(HttpServletRequest request) {
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");
Order order = (Order)session.getAttribute(user.getName());
    //如果session沒有Order對象,那么就是實例化一個
if(order==null) {
order = new Order();
}
return order;
}

/**
* 清空購物車
* @param request
*/
public static void clearCart(HttpServletRequest request){
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");
session.removeAttribute(user.getName());
}
}

  現(xiàn)在我們需要將這些類配置在Spring配置文件中,需要注意的是我們這里使用了聲明式事務(wù),因此需要引入對應(yīng)的schema,引入的方式在上一章已經(jīng)介紹,這里不再重復(fù)。配置文件的代碼如下:

Xml代碼
1.<beans default-autowire="byName"> 
2.    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
3.        <property name="jndiName" value="java:/comp/env/jdbc/order"/> 
4.    </bean> 
5.    <bean id="transactionManager"   
6.class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
7.        <property name="dataSource" ref="dataSource"/> 
8.        <property name="sessionFactory" ref="sessionFactory"/> 
9.    </bean> 
10.    <tx:annotation-driven /> 
11.    <bean id="sessionFactory"   
12.class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
13.        <property name="dataSource" ref="dataSource"/> 
14.        <property name="mappingResources"> 
15.            <list> 
16.                <value>cn/zxm/order/pojo/User.hbm.xml</value> 
17.                <value>cn/zxm/order/pojo/Order.hbm.xml</value> 
18.                <value>cn/zxm/order/pojo/Item.hbm.xml</value> 
19.            </list> 
20.        </property> 
21.        <property name="hibernateProperties"> 
22.            <props> 
23.                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> 
24.                <prop key="hibernate.show_sql">false</prop> 
25.                <prop key="hibernate.format_sql">true</prop> 
26.            </props> 
27.        </property> 
28.    </bean> 
29.    <bean id="hibernate" class="org.springframework.orm.hibernate3.HibernateTemplate"/> 
30.    <bean id="baseDAO" class="cn.zxm.order.dao.impl.BaseDAO" abstract="true"/> 
31.    <bean id="user" class="cn.zxm.order.pojo.User"/> 
32.    <bean id="userDAO" class="cn.zxm.order.dao.impl.UserDAOImpl" parent="baseDAO"/> 
33.    <bean id="orderDAO" class="cn.zxm.order.dao.impl.OrderDAOImpl" parent="baseDAO"/> 
34.    <bean id="itemDAO" class="cn.zxm.order.dao.impl.ItemDAOImpl" parent="baseDAO"/> 
35.    <bean id="userService" class="cn.zxm.order.service.impl.UserServiceImpl"/> 
36.    <bean id="orderService" class="cn.zxm.order.service.impl.OrderServiceImpl"/> 
37.    <bean id="itemService" class="cn.zxm.order.service.impl.ItemServiceImpl"/> 
38.</beans> 
<beans default-autowire="byName">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/comp/env/jdbc/order"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="dataSource" ref="dataSource"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>cn/zxm/order/pojo/User.hbm.xml</value>
<value>cn/zxm/order/pojo/Order.hbm.xml</value>
<value>cn/zxm/order/pojo/Item.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="hibernate" class="org.springframework.orm.hibernate3.HibernateTemplate"/>
<bean id="baseDAO" class="cn.zxm.order.dao.impl.BaseDAO" abstract="true"/>
<bean id="user" class="cn.zxm.order.pojo.User"/>
<bean id="userDAO" class="cn.zxm.order.dao.impl.UserDAOImpl" parent="baseDAO"/>
<bean id="orderDAO" class="cn.zxm.order.dao.impl.OrderDAOImpl" parent="baseDAO"/>
<bean id="itemDAO" class="cn.zxm.order.dao.impl.ItemDAOImpl" parent="baseDAO"/>
<bean id="userService" class="cn.zxm.order.service.impl.UserServiceImpl"/>
<bean id="orderService" class="cn.zxm.order.service.impl.OrderServiceImpl"/>
<bean id="itemService" class="cn.zxm.order.service.impl.ItemServiceImpl"/>
</beans>
  這里需要說明的是,為了簡化配置,我們使用了自動裝載。Hibernate所需要的信息完全在這里配置,從而取代了hibernate.cfg.xml的地位。事務(wù)管理器用的是專門為Hibernate3設(shè)計的,數(shù)據(jù)源是通過JNDI讀取的,這些都是需要特別注意的。
  現(xiàn)在可以開發(fā)web層了。由于Action和Form依賴于頁面,所以我們先考慮構(gòu)建頁面,所有的頁面位于應(yīng)用的order目錄下。根據(jù)需求,首先需要一個登錄頁,只需要用戶名和密碼輸入框。代碼如下(這里只列出和輸入相關(guān)部分的代碼,其它部分省略):

Html代碼
1.    <html:form action="/loginAction.do" method="get"> 
2.    <table width="400"  border="0" align="center" cellpadding="10" cellspacing="1" class="table-bgcolor"> 
3.      <tr class="table-body"> 
4.        <td class="table-head">賬號</td><td><html:text property="name" style="width:98%;"/></td> 
5.      </tr> 
6.      <tr class="table-body"> 
7.        <td class="table-head">密碼</td><td><html:password property="password" style="width:98%;"/></td> 
8.      </tr> 
9.      <tr class="table-body"><td></td><td><input type="submit" class="button" value="登錄"/></td></tr> 
10.  </table> 
11.</html:form> 
    <html:form action="/loginAction.do" method="get">
    <table width="400"  border="0" align="center" cellpadding="10" cellspacing="1" class="table-bgcolor">
      <tr class="table-body">
        <td class="table-head">賬號</td><td><html:text property="name" style="width:98%;"/></td>
      </tr>
      <tr class="table-body">
        <td class="table-head">密碼</td><td><html:password property="password" style="width:98%;"/></td>
      </tr>
      <tr class="table-body"><td></td><td><input type="submit" class="button" value="登錄"/></td></tr>
  </table>
</html:form>
  這里使用了Struts標(biāo)簽,使用它們時,需要確保在頁面頭部正確引入。注意在下面的form類中,屬性名和這里的名稱要一致。相關(guān)的form類代碼如下:

Java代碼
1.public class UserForm extends ActionForm {  
2.    private String name;  
3.    private String password;  
4.    private User user;  
5. 
6.    //setter和getter方法  
7.} 
public class UserForm extends ActionForm {
private String name;
private String password;
private User user;

//setter和getter方法
}
  然后寫一個Action用來處理登陸,代碼如下:

Java代碼
1.public class LoginAction extends Action {  
2.        private final Log log = LogFactory.getLog(LoginAction.class);  
3.        private UserService userService;  
4.        private User user;  
5.      
6.        public void setUserService(UserService userService) {  
7.            this.userService = userService;  
8.        }  
9.      
10.        public void setUser(User user) {  
11.            this.user = user;  
12.        }  
13.      
14.        /** 
15.@see 
16.  org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 
17.        */ 
18.        @Override 
19.        public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {  
20.            UserForm uf = (UserForm)form;  
21.            //克隆一份User對象,以此保證登錄信息的獨立性  
22.            User user2 = (User)BeanUtils.cloneBean(user);  
23.            //將用戶發(fā)來的數(shù)據(jù)放入User對象中  
24.            copyProperties(user2, uf);  
25.            //重新初始化表單  
26.            uf.reset(mapping, request);  
27.            //查詢用戶信息  
28.            User u = userService.getUser(user2);  
29.            //如果用戶不存在或者輸入信息不正確,就返回指定的頁面  
30.            if(u==null || !u.getPassword().equals(user2.getPassword()))  
31.                return mapping.findForward("fail");  
32.            user2.setId(u.getId());  
33.            user2.setPassword(u.getPassword());  
34.            //將查詢獲得的User對象放入form中,這樣頁面可以使用Hibernate的延遲加載  
35.            uf.setUser(u);  
36.            //將用戶信息存入session  
37.            request.getSession().setAttribute("user", user2);  
38.            //登錄成功,返回指定頁面  
39.            return mapping.findForward("welcome");  
40.        }  
41.} 
public class LoginAction extends Action {
    private final Log log = LogFactory.getLog(LoginAction.class);
private UserService userService;
private User user;

public void setUserService(UserService userService) {
this.userService = userService;
}

public void setUser(User user) {
this.user = user;
}

/**
@see
  org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
UserForm uf = (UserForm)form;
//克隆一份User對象,以此保證登錄信息的獨立性
User user2 = (User)BeanUtils.cloneBean(user);
//將用戶發(fā)來的數(shù)據(jù)放入User對象中
copyProperties(user2, uf);
//重新初始化表單
uf.reset(mapping, request);
//查詢用戶信息
User u = userService.getUser(user2);
//如果用戶不存在或者輸入信息不正確,就返回指定的頁面
if(u==null || !u.getPassword().equals(user2.getPassword()))
return mapping.findForward("fail");
user2.setId(u.getId());
user2.setPassword(u.getPassword());
//將查詢獲得的User對象放入form中,這樣頁面可以使用Hibernate的延遲加載
uf.setUser(u);
//將用戶信息存入session
request.getSession().setAttribute("user", user2);
//登錄成功,返回指定頁面
return mapping.findForward("welcome");
}
}

  針對登陸的類至此開發(fā)完成。剩下的就是配置,我們首先使用上一章講到的Spring與Struts整合的第三種方式,即使用Struts的Plug-in機制,struts-config.xml配置如下:

Xml代碼
1.<?xml version="1.0"?> 
2.<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> 
3.<struts-config> 
4.    <plug-in     className="org.springframework.web.struts.ContextLoaderPlugIn"> 
5.        <set-property property="contextConfigLocation" 
6.            value="/WEB-INF/classes/beans.xml" /> 
7.    </plug-in> 
8.</struts-config> 
<?xml version="1.0"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/classes/beans.xml" />
</plug-in>
</struts-config>

  在WEB-INF目錄下新建一個文件struts-order-config.xml,這個文件用于配置我們現(xiàn)在使用的模塊。Struts的模塊是按照目錄劃分的。在加入了這個模塊以后,相應(yīng)的web.xml中,給ActionServlet加入如下的參數(shù):

Xml代碼
1.<init-param> 
2.         <param-name>config/order</param-name> 
3.     <param-value>struts-order-config.xml</param-value> 
4.    </init-param> 
<init-param>
     <param-name>config/order</param-name>
     <param-value>struts-order-config.xml</param-value>
</init-param>
  如果有其它的模塊加入的話,只需按照這個格式添加即可。需要注意的是 confg/ 后面的參數(shù)必須是模塊對應(yīng)的目錄名。這樣應(yīng)用訪問特定模塊的時候,Struts會自動追加模塊的名稱。比如現(xiàn)在的登錄,頁面端表單中action對應(yīng)的值是/loginDispatcher.do,Struts會自動將它轉(zhuǎn)為/order/loginDispatcher.do。而Struts本身的配置文件在改動模塊名的時候,不需要作任何改動。這個應(yīng)用很小,沒有必要使用模塊化功能,這里使用它,只是為了演示。這樣的需求實際應(yīng)用中很常見。
  Struts-order-config.xml的配置如下:

Xml代碼
1.<struts-config> 
2.    <form-beans> 
3.            <form-bean name="userForm"   
4.type="cn.zxm.order.form.UserForm"/> 
5.        </form-beans> 
6.        <action-mappings> 
7.            <action path="/loginDispatcher" forward="/login.jsp"/> 
8.            <action path="/loginAction"   
9.input="/login.jsp"   
10.type="org.springframework.web.struts.DelegatingActionProxy" name="userForm"> 
11.                <forward name="fail" path="/loginDispatcher.do"/> 
12.                <forward name="welcome" path="/orderList.jsp"/> 
13.            </action> 
14.        </action-mappings> 
15.</struts-config> 
<struts-config>
    <form-beans>
<form-bean name="userForm"
type="cn.zxm.order.form.UserForm"/>
</form-beans>
<action-mappings>
<action path="/loginDispatcher" forward="/login.jsp"/>
<action path="/loginAction"
input="/login.jsp"
type="org.springframework.web.struts.DelegatingActionProxy" name="userForm">
<forward name="fail" path="/loginDispatcher.do"/>
<forward name="welcome" path="/orderList.jsp"/>
</action>
</action-mappings>
</struts-config>

  orderList.jsp用來顯示用戶的所有訂單。path的命名,應(yīng)該有一定的約定,比如只是簡單映射頁面,使用頁面名稱+Dispatcher的形式;處理頁面的請求的路徑使用頁面名稱+Action的形式,等等,這有利于將來我們使用通配符來簡化配置。這個問題我們后面會涉及到。
  在Spring配置文件中加入Action的定義,bean的名字對應(yīng)Struts中的path,只不過這個bean的名字包含了模塊名:

Xml代碼
1.<bean name="/order/loginAction"   
2.class="cn.zxm.order.action.LoginAction"/> 
<bean name="/order/loginAction"
class="cn.zxm.order.action.LoginAction"/>
  現(xiàn)在我們可以測試登錄了,我們在數(shù)據(jù)庫中輸入一個用戶的信息,用戶名和密碼都是zxm。打開瀏覽器,在地址欄輸入
http://www.zxm.net:8090/order/order/loginDispatcher.do
,頁面如圖9-2。

圖9-2 登錄
  輸入用戶名和密碼,輸入不正確的用戶名或者密碼,應(yīng)該返回登錄頁面,成功則進入訂單列表頁面,由于頁面端需要用到Hibernate的延遲加載特性,第一次訪問會拋出session closed的異常。

  現(xiàn)在我們構(gòu)建訂單顯示頁,訂單頁的代碼如下:

Html代碼
1.<%@ page language="java" contentType="text/html; charset=GBK" 
2.    pageEncoding="GBK"%> 
3.<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> 
4.<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> 
5.<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %> 
6.<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%> 
7.<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
8.<html> 
9.  <head> 
10.    <meta http-equiv="Content-Type" content="text/html; charset=GBK"> 
11.    <link rel="stylesheet" href="style.css" /> 
12.    <title>用戶訂單列表</title> 
13.  </head> 
14.  <body> 
15.  ${userForm.user.name},您好,您共提交了${fn:length(userForm.user.orders)}個訂單<br/> 
16.    <table width="100%"  border="0" align="center" cellpadding="10" cellspacing="1" class="table-bgcolor"> 
17.      <tr class="table-head"> 
18.        <th>id</th><th>訂單名稱</th><th>訂單描述</th><th>訂單生成日期</th> 
19.      </tr> 
20.      <logic:iterate id="order" property="user.orders" name="userForm"> 
21.        <tr class="table-body"> 
22.          <td><html:link action="/search_items.do?id=${order.id}">${order.id}</html:link></td> 
23.          <td>無</td> 
24.          <td>${order.description}</td> 
25.          <td>${order.createTime}</td> 
26.        </tr> 
27.      </logic:iterate> 
28. 
29.    </table> 
30.        <html:link action="/search_items.do">購物車</html:link><br/> 
31.        <html:link action="/itemDispatcher.do" style="button">訂購商品</html:link> 
32.  </body> 
33.</html> 
<%@ page language="java" contentType="text/html; charset=GBK"
    pageEncoding="GBK"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=GBK">
    <link rel="stylesheet" href="style.css" />
    <title>用戶訂單列表</title>
  </head>
  <body>
  ${userForm.user.name},您好,您共提交了${fn:length(userForm.user.orders)}個訂單<br/>
    <table width="100%"  border="0" align="center" cellpadding="10" cellspacing="1" class="table-bgcolor">
      <tr class="table-head">
        <th>id</th><th>訂單名稱</th><th>訂單描述</th><th>訂單生成日期</th>
      </tr>
      <logic:iterate id="order" property="user.orders" name="userForm">
        <tr class="table-body">
          <td><html:link action="/search_items.do?id=${order.id}">${order.id}</html:link></td>
          <td>無</td>
          <td>${order.description}</td>
          <td>${order.createTime}</td>
        </tr>
      </logic:iterate>

    </table>
        <html:link action="/search_items.do">購物車</html:link><br/>
        <html:link action="/itemDispatcher.do" style="button">訂購商品</html:link>
  </body>
</html>
  這里不但使用了Struts標(biāo)簽,還使用了JSTL,fn定義了一些有用的函數(shù),可以在EL中使用,比如計算集合長度的length。Logic標(biāo)簽庫是用于邏輯處理的標(biāo)簽庫,iterator用于遍歷集合,name屬性用于從request、session、pageContext或者application取值,相當(dāng)于調(diào)用它們的getAttribute()方法,property是對應(yīng)的屬性,可以使用表達式的方式,比如這里user.orders,相當(dāng)于調(diào)用對象的getUser().getOrders()方法,這種形式很常見,比如在Spring和ognl中就支持這種形式的表達式。id屬性是引用的名稱,其作用和下面的變量order相當(dāng):

Java代碼
1.for(Order order: 包含Order對象的集合){  
2.……  
3.} 
for(Order order: 包含Order對象的集合){
……
}
  上面用到的EL語言,前面已經(jīng)介紹過,這里不再贅述。
  這里引人注目的是Orders集合是從User對象中取出的,而在我們的代碼中并沒有這樣的賦值操作。事實上,這里用到了Hibernate的延遲加載特性,因此要求這里用到的User對象必須是一個持久化對象。這要求在處理頁面的時候,必須保證Hibernate的Session打開。因此我們應(yīng)該采用OpenSessionInView的模式,我們可以通過使用Spring提供的OpenSessionInViewFilter來實現(xiàn)這一模式,也可以通過使用Spring提供的OpenSessionInViewInterceptor,二者的作用相同。使用Filter的好處是開發(fā)者對它比較熟悉,使用Interceptor的方式要更為優(yōu)雅。因為我們將來要借助Spring的攔截器實現(xiàn)對用戶是否登錄的判斷,這里我們使用Interceptor的方式。不過這需要借助于SpringMVC來實現(xiàn),稍顯復(fù)雜。這就是Struts與Spring整合的第四種方式。詳細介紹如下。
  我們使用Spring的DispatcherServlet來分發(fā)請求,使用這個Servlet需要注冊一個Listener,web.xml配置如下:

Xml代碼
1.<?xml version="1.0" encoding="UTF-8"?> 
2.<web-app id="WebApp_ID" version="2.5" 
3.    xmlns="http://java.sun.com/xml/ns/javaee" 
4.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
5.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 
6.    <listener> 
7.        <listener-class> 
8.org.springframework.web.context.ContextLoaderListener  
9.</listener-class> 
10.    </listener> 
11.    <servlet> 
12.        <servlet-name>actions</servlet-name> 
13.        <servlet-class> 
14.org.springframework.web.servlet.DispatcherServlet  
15.</servlet-class> 
16.        <load-on-startup>1</load-on-startup> 
17.    </servlet> 
18.    <servlet-mapping> 
19.        <servlet-name>actions</servlet-name> 
20.        <url-pattern>*.do</url-pattern> 
21.    </servlet-mapping> 
22.</web-app> 
<?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">
<listener>
    <listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>actions</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>actions</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

  DispatcherServlet使用的配置文件,默認遵循這樣的規(guī)則:Servlet的名字-servlet.xml。這里是actions-servlet,它應(yīng)該位于WEB-INF下,這是一個標(biāo)準(zhǔn)的Spring配置文件。ContextLoaderListener也有需要一個默認的配置文件,名字是applicationContext.xml,也位于WEB-INFO下。我把我的配置信息都放入了applicationContext.xml中。我們需要去掉struts-config.xml中plug-in配置。好了,web.xml的信息就這么多?,F(xiàn)在需要修改Spring配置文件applicationContext.xml,在里面添加如下的配置:

Xml代碼
1.<bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> 
2.        <property name="flushMode" value="0"/> 
3.    </bean> 
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="flushMode" value="0"/>
</bean>
  flushMode屬性設(shè)置session的flush方式,這里設(shè)為0,表示永遠不使用自動flush,這是為了使用聲明式事務(wù)。

Xml代碼
1.<bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController"> 
2.        <property name="servletClass"> 
3.            <value>org.apache.struts.action.ActionServlet</value> 
4.        </property> 
5.        <property name="servletName" value="action"/> 
6.        <property name="initParameters"> 
7.            <props> 
8.                <prop key="config">/WEB-INF/struts-config.xml</prop> 
9.                <prop key="config/order">/WEB-INF/struts-order-config.xml</prop> 
10.                <prop key="debug">true</prop> 
11.            </props> 
12.        </property> 
13.    </bean> 
<bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController">
<property name="servletClass">
<value>org.apache.struts.action.ActionServlet</value>
</property>
<property name="servletName" value="action"/>
<property name="initParameters">
<props>
<prop key="config">/WEB-INF/struts-config.xml</prop>
<prop key="config/order">/WEB-INF/struts-order-config.xml</prop>
<prop key="debug">true</prop>
</props>
</property>
</bean>

  這里聲明了一個Controller,ServletWrappingController是為了Struts專門設(shè)計的,作用相當(dāng)于代理Struts的ActionServlet,下面的屬性都很好理解,我們看到和在web.xml的配置差不多,只不過形式的差異。
  最后我們需要把Struts的請求路徑和Controller關(guān)聯(lián)起來:

Xml代碼
1.<bean id="urlMapping"   
2.class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
3.        <property name="interceptors"> 
4.            <list> 
5.                <ref bean="openSessionInViewInterceptor" /> 
6.            </list> 
7.        </property> 
8.        <property name="mappings"> 
9.            <props> 
10.                <prop key="/*/*.do">strutsWrappingController</prop> 
11.            </props> 
12.        </property> 
13.    </bean> 
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="openSessionInViewInterceptor" />
</list>
</property>
<property name="mappings">
<props>
<prop key="/*/*.do">strutsWrappingController</prop>
</props>
</property>
</bean>
  這樣我們就可以使用Hibernate的延遲加載特性和Spring的聲明式事務(wù)了。注意intercptors屬性,我們可以添加自己的攔截器實現(xiàn),稍后我們會給出一個具體的實例。攔截器的順序也是要格外留意的。登錄成功后頁面如圖9-3。

圖 9-3 用戶訂單列表
  用戶注冊的流程和登錄一樣,注冊頁面和登錄一樣,這里我們就不在列出,只列出處理注冊的Action,代碼如下:

Java代碼
1.public class RegisterAction extends Action {  
2.    protected final Log log = LogFactory.getLog                  (RegisterAction.class);  
3.    private UserService userService;  
4.        private User user;  
5.      
6.        public void setUserService(UserService userService) {  
7.            this.userService = userService;  
8.    }  
9.      
10.        public void setUser(User user) {  
11.            this.user = user;  
12.        }  
13.      
14./** 
15.     * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 
16.     */ 
17.    @Override 
18.        public ActionForward execute(ActionMapping mapping,      
19.          ActionForm form, HttpServletRequest request,   
20.          HttpServletResponse response) throws Exception {  
21.        UserForm uf = (UserForm)form;  
22.        User u = (User)cloneBean(user);  
23.        copyProperties(u, uf);  
24.        uf.reset(mapping, request);  
25.        userService.save(u);  
26.        //用戶注冊失敗,則返回失敗頁面  
27.        if(u.getId()==null || u.getId()==0)  
28.            return mapping.findForward("fail");  
29.        //注冊成功,就返回訂單列表頁  
30.        uf.setUser(u);  
31.        request.getSession().setAttribute("user", u);  
32.        return mapping.findForward("welcome");  
33.    }  
34.} 
public class RegisterAction extends Action {
protected final Log log = LogFactory.getLog                  (RegisterAction.class);
private UserService userService;
private User user;

public void setUserService(UserService userService) {
this.userService = userService;
}

public void setUser(User user) {
this.user = user;
}

/**
* @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward execute(ActionMapping mapping,   
          ActionForm form, HttpServletRequest request,
          HttpServletResponse response) throws Exception {
UserForm uf = (UserForm)form;
User u = (User)cloneBean(user);
copyProperties(u, uf);
uf.reset(mapping, request);
userService.save(u);
//用戶注冊失敗,則返回失敗頁面
if(u.getId()==null || u.getId()==0)
return mapping.findForward("fail");
//注冊成功,就返回訂單列表頁
uf.setUser(u);
request.getSession().setAttribute("user", u);
return mapping.findForward("welcome");
}
}
  注冊頁面是register.jsp,對應(yīng)的path是/registerAction。然后我們在登錄頁面下加一個注冊按鈕,這樣用戶就可以從登錄頁轉(zhuǎn)到注冊頁。給注冊按鈕注冊一個響應(yīng)單擊的方法,代碼如下:

Js代碼
1.<script language="javascript">  
2.function register(){  
3.    window.location="registerDispatcher.do";  
4.}  
5.</script> 
<script language="javascript">
function register(){
    window.location="registerDispatcher.do";
}
</script>
  在struts-order-config.xml添加如下的配置:

Xml代碼
1.            <action path="/registerDispatcher" forward="/register.jsp"/> 
2.            <action path="/registerAction"   
3.input="/register.jsp"   
4.type="org.springframework.web.struts.DelegatingActionProxy" name="userForm"> 
5.                <forward name="fail" path="/registerDispatcher.do"/> 
6.                <forward name="welcome" path="/orderList.jsp"/> 
7.            </action> 
<action path="/registerDispatcher" forward="/register.jsp"/>
<action path="/registerAction"
input="/register.jsp"
type="org.springframework.web.struts.DelegatingActionProxy" name="userForm">
<forward name="fail" path="/registerDispatcher.do"/>
<forward name="welcome" path="/orderList.jsp"/>
</action>
  在applicationContext.xml中加入對應(yīng)的Action聲明:

Xml代碼
1.<bean name="/order/registerAction"   
2.class="cn.zxm.order.action.RegisterAction"/> 
<bean name="/order/registerAction"
class="cn.zxm.order.action.RegisterAction"/>
  這樣就可以進行登錄測試了。讀者可以測試注冊一個中文名,成功后,會發(fā)現(xiàn)用戶名是亂碼,這是由于Tomcat默認使用ISO-8859-1編碼,而我們使用的是GBK編碼。解決這個問題,針對請求方式,有不同的處理策略。比如對POST請求,我們需要使用過濾器進行重新編碼,對于GET請求,需要在Tomcat端口配置中設(shè)置編碼方式。下面我們分別予以介紹。
  我們可以自己實現(xiàn)這個過濾器,不過Spring已經(jīng)給我們提供了一個現(xiàn)成的實現(xiàn),它的配置方式如下:

Xml代碼
1.    <filter> 
2.        <filter-name>encodeFilter</filter-name> 
3.        <filter-class> 
4.org.springframework.web.filter.CharacterEncodingFilter  
5.</filter-class> 
6.        <init-param> 
7.            <param-name>forceEncoding</param-name> 
8.            <param-value>true</param-value> 
9.        </init-param> 
10.        <init-param> 
11.            <param-name>encoding</param-name> 
12.            <param-value>GBK</param-value> 
13.        </init-param> 
14.    </filter> 
15.    <filter-mapping> 
16.        <filter-name>encodeFilter</filter-name> 
17.        <url-pattern>*.do</url-pattern> 
18.    </filter-mapping> 
<filter>
    <filter-name>encodeFilter</filter-name>
    <filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GBK</param-
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
SSH實現(xiàn)的增刪改查實例
spring面試題
spring+hibernate整合
一份完整的Spring Hibernate DWR extJs的生成樹及下拉comBobo...
Struts2 Spring Hibernate搭建全解!
eclipse搭建SSH框架詳解
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服