(廣州醫(yī)科大學(xué) 信息技術(shù)教研室,廣州 511436)
隨著Web技術(shù)在互聯(lián)網(wǎng)上的發(fā)展,為解決web大型應(yīng)用開發(fā)的復(fù)雜性和提高效率等,許多輕量級(jí)的web框架技術(shù)應(yīng)運(yùn)而生,著名的有Struts2,Spring、Hibernate、MyBatis等[1]。在這些框架中,許多框架專注于為某一層提供解決方案,例如表示層或持久層。Spring框架致力于簡(jiǎn)化Java EE應(yīng)用程序的開發(fā)[2],將很多高質(zhì)量的開源框架整合在一起,為企業(yè)應(yīng)用開發(fā)提供一個(gè)全面的解決方案,降低企業(yè)開發(fā)的難度,提高開發(fā)效率。以購(gòu)書網(wǎng)站后臺(tái)管理系統(tǒng)的用戶管理為例,闡述基于Spring整合Spring MVC和Hibernate的SSH框架在Java Web項(xiàng)目開發(fā)中的應(yīng)用。
MVC(Model-View-Controller)是軟件工程中的一種軟件設(shè)計(jì)模式,把軟件系統(tǒng)分為模型(Model)、視圖(View)和控制器(Controller)3個(gè)部分[3]。圖1顯示MVC設(shè)計(jì)模式的關(guān)系模型。Model模型用于封裝與業(yè)務(wù)邏輯相關(guān)的數(shù)據(jù)和處理方法;視圖View是數(shù)據(jù)的呈現(xiàn),與用戶交互的界面,其組件一般是JSP或HTML;控制器Controller是接收請(qǐng)求,調(diào)用Model實(shí)現(xiàn)業(yè)務(wù),調(diào)用View顯示數(shù)據(jù),最終完成用戶請(qǐng)求。MVC設(shè)計(jì)模式將包含業(yè)務(wù)數(shù)據(jù)的模塊與顯示模塊的視圖解耦,不僅使得代碼復(fù)用性和組織性更好,而且使Web應(yīng)用的配置性和靈活性更好。

圖1 MVC關(guān)系模型
Spring MVC是一個(gè)實(shí)現(xiàn)了MVC設(shè)計(jì)模式的Web表示層框架,即用MVC設(shè)計(jì)模式的思想,將web層進(jìn)行職責(zé)解耦,目的就是簡(jiǎn)化web開發(fā)。Spring MVC提供了構(gòu)建 Web 應(yīng)用程序的全功能 MVC 模,有清晰的角色劃分,包括前端控制器(DispatcherServlet)、映射處理器(HandlerMapping)、映射適配器(HandlerAdapter)、視圖解析器(ViewResolver)、控制器(Controller)、驗(yàn)證器(Validator)、命令對(duì)象(Command Object)、表單對(duì)象(Form Object)等,其中DispatchServlet是SpringMVC的核心組件。SpringMVC的工作流程如圖2所示,Dispatcher Servlet接收到請(qǐng)求后,將請(qǐng)求委派為映射處理器,映射處理器和映射適配器根據(jù)請(qǐng)求所帶的URL信息進(jìn)行匹配選擇控制器,然后請(qǐng)求發(fā)送給選中的控制器。控制器在完成邏輯處理后,通常產(chǎn)生一些需要返回給瀏覽器顯示的信息,這些信息稱為模型(Model),并且需要用界面友好的視圖(通常是JSP)來(lái)顯示[4]。控制器把模型數(shù)據(jù)和用于渲染輸出的邏輯視圖名,連同請(qǐng)求一起發(fā)送回DispatcherServlet。DispatcherServlet使用視圖解析器將邏輯視圖名匹配為一個(gè)特定的物理視圖,然后將模型數(shù)據(jù)交付給物理視圖來(lái)渲染輸出。

圖2 Spring MVC工作流程
Spring MVC雖然和Struts2功能相似,但Struts2是類級(jí)別的控制攔截,一個(gè)Action類對(duì)應(yīng)一個(gè)請(qǐng)求URL上下文,而Spring MVC是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)請(qǐng)求URL的上下文。
Spring是一個(gè)輕量級(jí)的企業(yè)級(jí)開源框架,是為了解決企業(yè)級(jí)應(yīng)用程序開發(fā)的復(fù)雜性而創(chuàng)建[5]。Spring框架的核心是一個(gè)IoC容器,在這基礎(chǔ)上提供了大量實(shí)用的服務(wù),將很多高質(zhì)量的開源項(xiàng)目集成起來(lái)。Spring框架大約由20個(gè)功能模塊組成,這些模塊分為7個(gè)部分:分別是CoreContainer、DataAccess/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation及Test,如圖3所示。

圖3 Spring框架結(jié)構(gòu)
Spring的核心是控制反轉(zhuǎn)IoC和AOP面向切面編程技術(shù)[6],Spring核心容器定義了創(chuàng)建、配置和管理Bean的方式,管理各個(gè)Bean對(duì)象之間的依賴關(guān)系,能夠有效避免由于硬性編碼所造成的耦合度過(guò)于緊密的狀況;AOP功能可以輕松實(shí)現(xiàn)業(yè)務(wù)邏輯與系統(tǒng)服務(wù)(例如日志、事務(wù)等)的分離,使開發(fā)人員更加專注于業(yè)務(wù)邏輯實(shí)現(xiàn)。Spring是一個(gè)全面的解決方案,實(shí)現(xiàn)了表現(xiàn)層、業(yè)務(wù)層和持久層的整合,其主要目標(biāo)是讓現(xiàn)有的技術(shù)更加易用,絕不做重復(fù)實(shí)現(xiàn),只是對(duì)現(xiàn)有方案提供支持,使之更易用。
Hibernate是一個(gè)優(yōu)秀的Java持久層解決方案,是當(dāng)今主流的對(duì)象—關(guān)系映射(ORM,Object Relational Mapping)工具[7]。Hibernate的工作流程如圖4所示。

圖4 Hibernate工作流程
Configuration首先讀取并解析配置文件hibernate.cfg.xml,創(chuàng)建SessionFactory,SessionFactory是單例模式,只創(chuàng)建一次;接著SessionFactory創(chuàng)建Session接口,Session接口提供了操作數(shù)據(jù)庫(kù)的各種方法:save()、delete()、load()等,Session方法是非線程安全,每次執(zhí)行一次數(shù)據(jù)庫(kù)事務(wù),都需要?jiǎng)?chuàng)建Session對(duì)象;如果是增刪改操作,則由Session對(duì)象開啟一個(gè)事務(wù)對(duì)象Transaction,保證數(shù)據(jù)庫(kù)操作的完整性如果數(shù)據(jù)庫(kù)操作正常則提交事務(wù),否則回滾;如果是查詢操作,則由Session創(chuàng)建一個(gè)Query接口對(duì)象來(lái)執(zhí)行查詢,查詢不需要開啟事務(wù)。數(shù)據(jù)庫(kù)訪問(wèn)結(jié)束,需要關(guān)閉Session對(duì)象,如果開啟Transaction對(duì)象,也要關(guān)閉。在查詢中,Query接口用于HQL查詢,HQL(Hibernate Query Language)是Hibernate中最常用的一種面向?qū)ο蟮牟樵冋Z(yǔ)言,可以理解繼承、多態(tài)和關(guān)聯(lián)之類的概念[8]。
Hibernate的優(yōu)勢(shì)在于數(shù)據(jù)庫(kù)操作對(duì)象化,使用數(shù)據(jù)庫(kù)方言機(jī)制和HQL查詢語(yǔ)言,無(wú)須關(guān)心數(shù)據(jù)庫(kù)類型,便于移植[9];Hibernate封裝了JDBC,還封裝了底層數(shù)據(jù)庫(kù)事務(wù)處理,極大提高了開發(fā)效率;為了減少訪問(wèn)物理數(shù)據(jù)庫(kù)的次數(shù),還使用了緩存機(jī)制,從而提高了程序的運(yùn)行性能。
這里的SSH是Spring MVC、Spring和Hibernate的簡(jiǎn)稱,這是當(dāng)前主流的Web應(yīng)用項(xiàng)目架構(gòu)。Java EE經(jīng)過(guò)多年的發(fā)展,已經(jīng)形成一套成熟的系統(tǒng)結(jié)構(gòu),系統(tǒng)一般分為四層:表示層、控制層、業(yè)務(wù)層和數(shù)據(jù)持久層。在SSH框架下,其系統(tǒng)的程序結(jié)構(gòu)如圖5所示。

圖5 SSH系統(tǒng)的程序結(jié)構(gòu)
表示層一般為JSP頁(yè)面,返回用戶請(qǐng)求響應(yīng);控制層由Spring MVC框架負(fù)責(zé),轉(zhuǎn)發(fā)請(qǐng)求并調(diào)用業(yè)務(wù)層方法處理請(qǐng)求;業(yè)務(wù)層即Service層,是系統(tǒng)架構(gòu)中體現(xiàn)核心價(jià)值的部分,它主要集中在業(yè)務(wù)規(guī)則的制定、業(yè)務(wù)流程的實(shí)現(xiàn)等與業(yè)務(wù)需求有關(guān)的系統(tǒng)設(shè)計(jì)上[10]。業(yè)務(wù)層處在控制層和持久層中間,對(duì)持久層而言,它是調(diào)用者,對(duì)控制層而言,它是被調(diào)用者。數(shù)據(jù)持久層由Hibernate框架實(shí)現(xiàn)。
在圖5中,來(lái)自客戶端的Request請(qǐng)求被由DispatcherServlet前端控制器接收,DispatcherServlet把請(qǐng)求派發(fā)給Controller控制器,Controller調(diào)用業(yè)務(wù)方法Service來(lái)實(shí)現(xiàn)業(yè)務(wù),如需要訪問(wèn)數(shù)據(jù)庫(kù),業(yè)務(wù)類就調(diào)用Dao(Data Access Object,數(shù)據(jù)訪問(wèn)對(duì)象)數(shù)據(jù)操作類訪問(wèn)數(shù)據(jù)庫(kù)。而Dao類則需要使用Hibernate的SessionFactory(會(huì)話工廠)提供的Session會(huì)話來(lái)實(shí)現(xiàn)具體操作,Session通過(guò)Connection來(lái)實(shí)現(xiàn)增刪改擦操作,而Connection由數(shù)據(jù)源(DataSource)來(lái)提供。
Controller、Service、Dao都納入Spring容器管理,Session由SessionFactory創(chuàng)建并管理,Connection由DataSource創(chuàng)建并管理,所以也需要把SessionFactory和DataSource加入Spring容器管理。
購(gòu)書網(wǎng)站主要包括兩個(gè)部分:前臺(tái)部分和后臺(tái)管理部分。前臺(tái)部分主要服務(wù)于普通用戶,用戶可以查看圖書信息,登錄,注冊(cè),購(gòu)買和進(jìn)行個(gè)人信息管理、購(gòu)物車管理、下單等操作;后臺(tái)管理模塊則是管理員對(duì)書店進(jìn)行業(yè)務(wù)管理,其后臺(tái)系統(tǒng)的基本功能模塊設(shè)計(jì)如圖6所示。


圖6 購(gòu)書網(wǎng)站后臺(tái)管理的基本功能結(jié)構(gòu)
首先進(jìn)行系統(tǒng)的SSH框架整合,整合工作主要是Spring與Hibernate整合和Spring與SpringMVC的整合,整合以后,所有實(shí)例對(duì)象納入Spring容器管理。整合分三步:
第一步,整合Spring和Hibernate。在Spring配置文件applicationContext.xml中,把外部導(dǎo)入的Properties屬性文件、Hibernate的數(shù)據(jù)源對(duì)象、sessionFactory對(duì)象、事務(wù)管理等配置進(jìn)來(lái),Hibernate.cfg.xml就不再需要。接下來(lái)配置持久類映射文件的路徑和Dao以及Service。為了簡(jiǎn)化配置工作,Dao和Service可以采用注解方式注入Spring容器。為了使用注解,需要在配置文件中加入兩個(gè)配置,見下列代碼。
上述配置的代碼,可以自動(dòng)掃描com.*包下的所有注解類。
第二步,Spring整合Spring MVC。需要單獨(dú)使用一個(gè)配置文件springMVC.xml,該文件放在src下或WEB-INF下均可。Spring MVC的配置文件通常有三個(gè)常用的配置,分別是:
1)
2)
3)
此外,spring MVC的配置文件還需要配置視圖解析器ViewResolover,表示把用戶響應(yīng)指定給某個(gè)表現(xiàn)層技術(shù),例如JSP、JSTL,XLST和velocity等,通常設(shè)定為JSP。如果使用JSP,則配置的視圖解析器是InternalResourceViewResolver;如果JSP頁(yè)面需要使用JSTL標(biāo)簽,則增加
第三步,在Web.xml中配置Spring監(jiān)聽器ContextLoaderListener和SpringMVC的核心DispatcherServlet,以及其他一些參數(shù),例如過(guò)濾器filter和上下文參數(shù)context-param。這樣Spring MVC就可以監(jiān)聽來(lái)自客戶端的請(qǐng)求,并把請(qǐng)求轉(zhuǎn)發(fā)給DispatcherServlet處理。
后臺(tái)管理系統(tǒng)的功能主要是與后臺(tái)數(shù)據(jù)庫(kù)交互進(jìn)行管理業(yè)務(wù)數(shù)據(jù),與后臺(tái)數(shù)據(jù)庫(kù)的交互主要是數(shù)據(jù)庫(kù)增加、修改、刪除和查詢等操作。所以這里以用戶管理為例,主要講述在SSH框架下用戶管理功能的實(shí)現(xiàn)。
6.3.1 持久化類實(shí)體層
使用Hibernate來(lái)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)持久化,首先要建立持久化類以及配置持久化類和數(shù)據(jù)庫(kù)表的一一映射關(guān)系。本系統(tǒng)的用戶管理涉及兩個(gè)數(shù)據(jù)表:User用戶表和Role角色表,因此先創(chuàng)建與數(shù)據(jù)庫(kù)表字段一一對(duì)應(yīng)的持久化類User和Role,然后配置持久化類與數(shù)據(jù)庫(kù)表之間的映射關(guān)系。在Hibernate中,有兩種方式來(lái)實(shí)現(xiàn)該映射關(guān)系,一種是使用映射配置文件,即建立User.hbm.xml,還在改文件中表與表之間的關(guān)聯(lián)關(guān)系;另一種是使用注解方式。本文采用注解來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)表與持久類的映射關(guān)系,以及User持久化類和Role持久化類之間多對(duì)一關(guān)聯(lián)關(guān)系。具體見如下代碼:
@Entity //聲明User類為POJO類
@Table(name="user") //和User數(shù)據(jù)庫(kù)表建立映射關(guān)系
public class User {
//省略其他屬性和注解
@ManyToOne(cascade=CascadeType.ALL,optional=true) //多對(duì)一關(guān)系的注解
@JoinColumn(name="role_id") //User表的外鍵role_id
private UserRole userRole=new UserRole();
//省略屬性的getter/setter方法
}
與創(chuàng)建hbm.xml映射配置文件相比,使用注解可以減少代碼工作量,其他相關(guān)注解的說(shuō)明在此不再贅述。
6.3.2 Dao數(shù)據(jù)訪問(wèn)層
用戶管理模塊的Dao數(shù)據(jù)訪問(wèn)層是通過(guò)Hibernate直接訪問(wèn)數(shù)據(jù)庫(kù),定義并實(shí)現(xiàn)用戶增加、修改、刪除、查詢和修改角色等Dao方法。系統(tǒng)面向接口編程,采用基于泛型
首先編寫泛型的BaseDao

圖7 基于泛型Dao的類圖
由于Spring框架提供了對(duì)Dao組件的支持,支持用HibernateTemplate模板進(jìn)行數(shù)據(jù)庫(kù)持久化訪問(wèn),所以在BaseDaoImpl
public abstract class BaseDaoImpl
protected SessionFactory sessionFactory;
private Class
public BaseDaoImpl(){
//當(dāng)BaseDaoImpl
entityClass=(Class
}
public void save(T instance){
getHibernateTemplate().save(instance); }
//省略其他方法
}
使用HibernateTemplate的好處顯而易見,只要傳進(jìn)實(shí)體類,不需要編寫太多的SQL語(yǔ)句,就可以進(jìn)行數(shù)據(jù)庫(kù)持久化操作,再加上泛型的使用,便大大提高了程序的開發(fā)效率。
6.3.3 業(yè)務(wù)邏輯層
用戶管理的業(yè)務(wù)邏輯層主要是實(shí)現(xiàn)與用戶和角色相關(guān)的業(yè)務(wù)邏輯操作,包括復(fù)雜的業(yè)務(wù)流程處理,也可以調(diào)用底層的Dao方法來(lái)實(shí)現(xiàn)之。在業(yè)務(wù)邏輯層的實(shí)現(xiàn)上,系統(tǒng)也采用泛型模式建立泛型接口的BaseService
public interface BaseService
//聲明增刪改查的業(yè)務(wù)方法。
public void save(T instance);
public List
//省略其他方法
}
public abstract class BaseServiceImpl
private BaseDao
public void setBaseDao(BaseDao baseDao) {
this.baseDao = baseDao;
}
public void save(T instance) {
baseDao.save(instance);//實(shí)現(xiàn)save方法
}
//省略其他方法
}
public interface IUserService extends BaseService
//聲明獨(dú)有的方法
public void login(){ }
}
@Service("userService")
public class UserService extends BaseServiceImpl
@Autowired
private UserDao userDao;
public void setUserDao(UserDao userDao) {
//為泛型父類注入具體的userDao
super.setBaseDao(userDao);
this.userDao = userDao;
}
public void login() {
//代碼略
}
}
在復(fù)雜大型的實(shí)際應(yīng)用中,還可以把泛型的Dao和Service獨(dú)立成一個(gè)核心包,其他的模塊例如用戶管理、訂單管理等可以直接繼承核心包里的泛型BaseDao和泛型BaseService,這樣項(xiàng)目的程序結(jié)構(gòu)更加清晰明了。基于泛型接口的Dao層和Service層搭建好,具體Dao實(shí)現(xiàn)類和Service實(shí)現(xiàn)類的代碼量少很多,很大程度上降低了程序員的工作量,使程序員集中精力解決業(yè)務(wù)邏輯問(wèn)題,加快系統(tǒng)的開發(fā)速度。
6.3.4 Web控制層
Web控制層由Spring MVC負(fù)責(zé)。系統(tǒng)為用戶管理模塊編寫了一個(gè)UserController控制器類,包括用戶的登錄、注冊(cè)、用戶增加、修改、查詢、角色修改等業(yè)務(wù)請(qǐng)求處理方法。來(lái)自客戶端的用戶請(qǐng)求由Spring MVC核心——DispatcherServlet接收,并把請(qǐng)求派發(fā)到Controller控制器的相應(yīng)的處理用戶請(qǐng)求的方法上,該方法調(diào)用業(yè)務(wù)邏輯層的Service方法來(lái)處理用戶請(qǐng)求,然后把ModelAndView返回給DispatcherServlet。由于DispatcherServlet已經(jīng)配置在Web.xml中,開發(fā)人員只需編寫Controller類即可。UserController類的部分代碼示例如下:
@Controller //注冊(cè)為控制器類
//表示“/user”路徑下的所有URL請(qǐng)求都交由UserController處理
@RequestMapping(value="/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private UserRoleService userRoleService;
//表示“/user/admin”的URL請(qǐng)求交給gotoadmin方法處理。
@RequestMapping(value="/admin")
public String gotoadmin() {
return "admin-index";
}
}
編寫Controller類,一是需要聲明所需要的Service接口,二是通過(guò)注解注冊(cè)Controller類和請(qǐng)求地址映射及參數(shù)綁定。其中注解@Controller來(lái)將該類注冊(cè)為Controller類,注解@RequestMapping來(lái)處理請(qǐng)求地址映射,注解@PathVariable或@RequestParam等進(jìn)行參數(shù)綁定,三是編寫具體操作方法,至此可實(shí)現(xiàn)控制層功能。
6.3.5 表示層
Spring MVC 有一個(gè)標(biāo)簽庫(kù),其標(biāo)簽庫(kù)的jar包為spring.jar,需要加入項(xiàng)目庫(kù)文件中。使用Spring MVC標(biāo)簽可以將請(qǐng)求參數(shù)綁定到命令對(duì)象上,由于系統(tǒng)已經(jīng)在Spring MVC的配置文件中的配置了JSP作為視圖響應(yīng)技術(shù),可以容易地使用Spring MVC標(biāo)簽或JSTL標(biāo)簽進(jìn)行含有數(shù)據(jù)綁定的JSP頁(yè)面開發(fā)。
本系統(tǒng)采用Bootstrap作為前端響應(yīng)技術(shù)。Bootstrap是目前很受歡迎的前端開發(fā)工具,內(nèi)置很多漂亮的樣式,代碼非常簡(jiǎn)潔,易于修改,具有靈活的響應(yīng)式柵格系統(tǒng)和良好的瀏覽器兼容性支持,可以支持桌面瀏覽器和移動(dòng)瀏覽器,本系統(tǒng)采用Bootstrap框架,就實(shí)現(xiàn)了后臺(tái)運(yùn)行一份代碼,用戶就可以根據(jù)需要隨時(shí)在移動(dòng)端、PC端進(jìn)行交易。圖8展示了桌面瀏覽器的用戶管理界面。圖9展示了移動(dòng)端的圖書列表界面。

圖8 桌面端的后臺(tái)用戶管理


圖9 移動(dòng)端圖書管理界面
本文介紹了Spring MVC、Spring和Hibernate的工作原理和特點(diǎn),Spring MVC充當(dāng)web層的控制器,Spring容器管理SpringMVC和Hibernate,進(jìn)行業(yè)務(wù)邏輯處理,Hibernate負(fù)責(zé)與后臺(tái)數(shù)據(jù)庫(kù)進(jìn)行交互實(shí)現(xiàn)持久層。以及介紹了基于SSH框架的購(gòu)物網(wǎng)站后臺(tái)管理基本模塊的設(shè)計(jì),并以后臺(tái)系統(tǒng)的用戶管理模塊為例,簡(jiǎn)要闡述了在SSH框架下的Web項(xiàng)目開發(fā)的設(shè)計(jì)與實(shí)現(xiàn)。基于SSH架構(gòu)的Web應(yīng)用程序會(huì)具有良好的擴(kuò)展性和復(fù)用性,能充分體現(xiàn)基于MVC設(shè)計(jì)模式的三層體系結(jié)構(gòu)的特點(diǎn)和優(yōu)點(diǎn),并且層與層之間的高度解耦,使系統(tǒng)更加容易更新與維護(hù),適應(yīng)快速變化的用戶需求。