一种基于Struts2 框架的Web 分页模型的设计与实现

2013-08-29 09:38崔行臣张明光
山东科学 2013年4期
关键词:表示层视图代码

崔行臣,张明光

(山东广播电视大学现代教育技术中心,山东 济南 250014)

在Web 应用软件开发中,通常要对数据进行多种条件的查询。在传统设计中,通常是客户一次从服务器中查询所要的数据并显示到客户端,但当符合条件的数据量较大时,就会增加服务器的通信负载,减慢Web 服务器的响应速度,用户浏览数据的体验效果较差。因此,适当的分页技术是十分必要的。如果直接利用数据库管理系统提供的分页功能来对数据分页,性能比较高,但是不同的数据库实现的方法各不相同,缺乏通用性。在基于JavaEE 平台上,分页方法传统上使用在JSP 中编码的方式来实现,将页面的业务操作、控制逻辑和显示都放在JSP 中,直接在其页面上对数据进行操作,最后将所取得的数据在页面进行分页显示。这种方法的缺点是应用系统框架之间高度耦合,分页程序的重用性和移植性差[1-2]。

针对以上问题,本文利用基于MVC 模式的Struts2 架构来实现一种高效的可移植的Web 数据分页方法,依托良好的层次机构设计达到显示逻辑和业务逻辑分离、代码重用性高的目的。

图1 Struts2 的数据流向图Fig.1 Data flow diagram of Struts2

1 MVC 模式和Struts 框架

MVC 把一个Web 应用分成3 个基本部分:Model (模型)、View (视图)和Controler(控制器),这3 个部分以最小的耦合协同工作,从而提高系统的可扩展性和可维护性。模型部件是软件所处理问题逻辑在独立于外在显示内容和形式情况下的内在抽象,它封装了问题的业务数据和逻辑。视图部件把表示模型数据和逻辑关系的信息以特定形式展示出来。控制器是使模型和视图协同工作的部件,把不同的模型和不同的视图结合在一起,完成不同的请求。模型、视图与控制器的分离,使得多个视图共享一个模型,如果用户通过视图的控制器改变了模型数据,所有其他依赖于这些数据的视图都应反映这些变化,也减少了代码维护量。采用MVC 模式开发有利于软件工程化管理,每一层各司其职,提供良好的工程结构并降低各个组件之间的耦合性。

Struts2 是实现MVC 的一个优秀框架,提供了较好的层次分隔能力。Struts2 框架中使用Servlet 过滤器来作为控制器FilterDispatcher,它过滤请求并决定由哪个Action 来处理当前请求。Action 在Struts2 中作为模型而存在,主要有两个功能:一是进行数据的传递,Action 中的成员属性不一定封装用户的请求参数,也可以封装了Action 需要传入下一个页面显示的值;二是可以用来调用业务逻辑处理请求,当Action 把处理请求处理完毕后,会返回一个逻辑视图。视图表现形式很多,既支持JSP,也支持FreeMaker 等模版技术[3]。Struts2 的数据流向图如图1 所示。

2 Java EE 平台中几种典型的分页技术

2.1 基于SQL 分页算法

Mysql、Oracle,DB2 等数据库管理系统(DBMS)都提供了自身的数据库分页方法,而且SQL 都对其进行了优化处理:Oracle 使用伪数列rownum 来限制结果集的大小和起始位置;Mysql 使用limit 子句来限制返回结果集的条数;Sqlserver 使用top 关键字可以实现分页。这类方法属于数据层分页技术,即从数据库查询时就进行过滤截取。虽然各种数据库都提供了相应的方法,但是在实际程序开发中,如果数据来源由一种数据库迁移到另外一种数据库时,由于SQL 分页代码不兼容,需要修改大量的程序来适应这种变换,维护起来很困难,也不符合软件工程开发的思想。

2.2 JSP 分页方法

将页面的显示、控制逻辑及业务操作都放在JSP 中,直接在其页面进行数据操作。这种方法虽然简洁直观,但缺点是过多的业务逻辑和业务操作都混杂在显示层页面,不仅程序员难以维护,而且应用系统框架模糊、相应组件之间紧密耦合,严重违背了面向对象程序设计原理和软件设计模式中提倡的单一职责原则和迪米特法则。

2.3 用ResultSet 移动游标实现分页

在分页的地方直接使用jdbc 提供的ResultSet 对象来处理数据,ResultSet 可以看作是一张表,包含了符合SQL 查询语句条件的所有行以及查询的列标题和值。ResultSet 直接在数据库上建立游标,并维护指向其当前数据行的光标,使游标定位结果集。但由于游标是放在内存中,在整个会话期间将一直占用内存,并不释放数据库连接和ResultSet 对象。这种方式在操作大型数据和访问用户很多的时候,有可能导致DBMS 因为资源耗尽而崩溃。

2.4 将查询结果缓存在HttpSession 或变量中实现分页

这种方式一般不使用,其缺陷是用户看到的可能是过期数据并且会占用大量Web 容器内存[4]。

2.5 使用标签库

将分页查询和显示做成JSP taglib,简化JSP 代码,使用简单灵活[5]。目前比较流行的分页标签库有displaytag、Pager-taglib 等。

3 基于Struts2 框架的分页技术方案

针对以上几种分页方法存在的问题,在实践中总结出针对中小型Web 应用系统比较好的分页方法:检索指定页面的显示数据,用JavaBean 来封装分页操作和数据。每次翻页的时候只从数据库里检索页面大小的块区的数据。这样查询出的记录数很少,网络传输数据量不大,使用连接池技术能缩短建立数据库连接过程时间。在架构设计上采用Struts2 框架进行模型层、表示层和控制层的分离。各层完成独立的功能,相互之间耦合度较小,具有易扩展和易移植的优点[6]。

图2 分页查询流程框架Fig.2 Framework of paging query process

(1) 模 型 层:采 用JavaBean 来封装页面请求参数属性,如显示第几页,查询结果等。

(2)表示层:表示层的主要任务,一是向业务逻辑层发出需要显示某页数据集的HTTP 请求,在该数据集请求中包括需要显示的总共记录数、共要显示多少页、每页的最大数以及当前位于第几页等;二是接受业务逻辑层返回的记录结果集,并且显示为记录列表[4]。在本文设计的分页模型中采用JSP 来显示分页数据,为了增强显示层的通用性和可移植性,在JSP 中使用Struts 框架的标签库,可以把表现和逻辑分离并且也使得页面显示功能不具体绑定在某个显示框架下面,侧重于提供HTML 表示层数据。查询分页数据和分页导航代码在表示层都利用Struts 标签显示。

(3)控制层(Controller):采用Struts2 提供的FilterDispatcher 类作为核心控制器,该控制器作为一个Filter运行在Web 应用中,负责拦截用户请求后根据映射配置文件struts.xml 再把控制转交到业务逻辑层(Business Logic)相应的处理器。引入业务逻辑层的意义在于实现显示、控制和模型的完全分离,提高扩展性和重用性,并减轻了FilterDispatcher 的负担。

(4)业务逻辑层:采用Struts2 中的Action 类进行业务组件的处理。在Action 中,分页相关属性被映射成普通的POJO。主要作用是处理来自表示层的请求,并依据该请求向数据层获得当前页的数据记录,并将结果集返回给表示层[7]。

(5)Dao 层:负责与数据库的交互操作。传递相应的参数,根据Java 多态机制,调用相应的数据库管理系统,查询所需数据。为了充分利用已经建立的连接,采用数据源连接池技术来提高查询速度。

基于Struts2 框架的分页查询流程框架和主要类设计如图2 所示。

4 设计实现

4.1 主要类设计

PageBean 类:作为业务模型封装了数据库查询条件以及提取和保存数据的操作,记录了记录总数、当前页及每页显示的记录数。

Page 类:用于产生分页信息的对象,实现了用于显示分页信息的基本方法。

PagedStatement 抽象类:为了使分页对所有数据库具有更好的扩展性,使用模板设计模式来抽象数据库操作,这些操作包括执行查询取得一页数据和数据库管理类进行交互等。抽象类PagedStatement 根据查询语句和页码查询出当前页数据,返回的数据类型没有具体指定,可根据需要实现以特定方式组织数据的子类,如RowSetDataPage 类以RowSet 类型封装数据,ListDataPage 类以List 集合封装数据等等。方法定义为:public ListPage execute Query Of List Page()throws SQLException。查询当前页数据时,根据具体的数据库类型,利用Java 的多态机制来调用相应的实现类获取数据。针对Sqlserver 数据库的分页查询,实现类定义为PagedStatementSQLServerImpl extends PagedStatement,如果要扩展到 Oracle 分页数据,只需添加PagedStatement 的Oracle 实现类即可。

4.2 业务逻辑层调用及表示层高效移植实现

在业务逻辑层action 中,以sqlserver 数据库为例,调用分页组件的分页处理方法为:

PagedStatement pst=new PagedStatementSQLServerImpl(sql,pageno,pageNum);

ListDataPage listpage=pst.executeQueryOfListPage();

this.userlist=listpage.getList();∥当前页记录数据

this.pageBar=listpage.getHTML("doQuery","pageno");∥页面分页代码

返回的结果集封装在List 集合中,封装数据结果的类,如ListDataPage 类有getHTML()方法,用于生成分页代码,系统提供默认的分页代码,如上下型和随意型的分页模型[8],如果用户不满意,可以编写自己所需的分页代码。生成的前台页面分页导航条代码封装在pageBar 变量中,根据Struts2 机制,注入到页面中,在表示层利用Struts2 强大的标签功能可以很方便地显示分页数据和分页链接代码。如果改用其它数据库,调用相应的实现类即可。

对于分页代码,可以放在一个单独的文件中(page.jsp),假设原来的显示页面没有分页,只要在页面的分页导航位置以 <jsp:include >方式将page.jsp 包含进去,表示层就完成了,完全不用修改原有的代码。因为在表示层生成的分页链接代码中,提交表单的动作已经指向当前业务逻辑Action。每次请求提交表单时,页码变量pageno 被注入到相应业务逻辑Action,根据pageno 来获取新的一页数据。示例代码如下:

<form name="pageForm" method="post" action="" > <div class="pagestyle" >

<s:property escape="false" value="pageBar"/>∥生成分页链接代码

</div > </form >

以上分页代码经服务器解析后,生成分页导航条的HTML 代码,包括“第几页”、“共几页”,“上一页”、“下一页”、“首页”和“末页”连接和“转到第几页”的导航选择列表。

4.3 应用及性能分析

以上讨论的分页模型已在某高校各部门网站系统中得到实际应用,在构造各级网站时只要涉及到数据分页的页面,都可以使用该方案来实现。操作步骤为:(1)在业务逻辑层调用接口;(2)在表示层分页位置导入分页代码文件。测试性能比较如表1 所示。

从表1 可以看出,本文提出的解决方案主要从软件工程的角度来改进传统的分页查询方式,在架构设计、维护及用户体验方面具有明显的优势。在时间上,在开发环境JDK1.6、Tomcat6.0 下,对于10 万条数据查询请求,平均响应时间为0.5 s,而本文提到的其它技术对10 万条数据记录查询时,基于SQL 分页方法平均响应时间为0.6 s,JSP 分页方法最好时间也在1 s 以上。

表1 本文模型与传统方式的性能比较Table 1 Performance comparison of the presented model and the traditional model

5 结语

经测试证明,本文提出的基于MVC 思想和Struts2 架构设计的数据分页模型具有良好的可扩展性、可维护性及优秀的解耦性,获得了较高的用户满意度。该方案存在的问题在于框架模型管理不方便,下一步将研究采用Spring 框架来集成管理该模型。此外,对于频繁读取的数据(如:相邻上下页),为节省时间,可以只访问一次底层数据库而把符合条件的数据全部读取至Web 服务器,并在其上生成一个XML 文件,以后客户端直接和XML 文件交互[9],这也是今后研究的方向。

[1]曹晋,胡谷雨.基于jsp 技术的数据库查询分页显示[J].计算机技术与发展,2007,17(5):225 -227.

[2]黄栎桥,陆鑫.基于Struts 框架的Web 数据库分页技术[J].计算机工程,2008,28(6):298 -301.

[2]李刚.Struts2.1 权威指南——基于webwork 核心的MVC 开发[M].北京:电子工业出版社,2009.

[3]刘启文,周大海,夏秀峰.Web 应用中可扩展分页技术的研究与实现[J].计算机应用,2006,26(12):179 -181.

[4]何玲娟,蚁 龙,刘连臣.一种松耦合高复用MVC 模式的Web 分页实现[J].计算机工程与应用,2007,43(15):95 -97.

[5]吴东庆,张新猛,王前,等.基于SSH 架构的分页查询标签的研究与实现[J].仲恺农业工程学院学报,2010,23(1):45 -48.

[6]王瑞波.一种分页查询优化方法的研究与实现[D].北京:北京化工大学,2009.

[7]张俐.基于MVC 模式的分页组件应用[J].计算机工程,2011,37(21):255 -257.

[8]顾志峰,李涓子.Web 应用程序分页策略的研究[J].计算机工程,2005,31(21):60 -62.

[9]勾成图,张璟,李军怀.海量数据分页机制在Web 信息系统中的应用研究[J].2005,25(8):1926 -1929.

猜你喜欢
表示层视图代码
基于Spring的企业级Web项目架构设计研究
创世代码
创世代码
创世代码
创世代码
5.3 视图与投影
视图
Y—20重型运输机多视图
SA2型76毫米车载高炮多视图
ASP.NET三层构架解析