摘要
信息时代的到来,给电子商务带来了无限活力,电子商务网站已经显示出欣欣向荣的繁荣景象。基于这一历史背景,本论文介绍了基于J2EE标准规范,并采用其推荐的实现技术JSP(java server pages)、Servlet等对一个典型电子商务网站(网络书店)的实现,并在开发过程中遵照RUP(Rational统一过程)理论,应用统一建模语言UML(Unified Modeling Language)对整个开发过程建立模型,据此建立一个三层B/S架构的电子商务平台。
关键字
J2EE;JSP;struts;网络书店;电子商务
Abstract
The coming of information times has brought immensurable energy to electronic business, and electronic business net has shown a prosperous vision. Based on this history background, this thesis introduced the realization of a model E-business net (bookshop net), it based on J2EE standard specification, and used the technique of JSP, Servlet, and so on. During the course of development, I conformed to Rational Unified Process theory, establishing model to total development process by Unified Modeling Language, and according to this establishing a three tiers B/S framework E-Business platform.
Key Words
J2EE;JSP;struts;Network Bookstore;Electronic Commerce
目录
1 引言
1.1 网络书店的研究意义
随着Internet网络技术的发展,人们的生活和Internet的关系越来越紧密,如何通过Internet抓住商机成为摆在人们面前的一个重要话题,电子商务就是在此环境下诞生和发展起来。
通俗的地说,所谓电子商务,就是在网上开展商务活动-——当企业将它的主要业务通过企业内部网(Intranet)、外部网(Extranet)以及Internet与企业的职员、客户、供销商以及合作伙伴直接相连时,其中发生的各种活动就是电子商务。电子商务基于Internet/Intranet,包括了从销售、市场到商业信息管理的全过程。
目前,大多数电子商务系统是基于WEB技术,并且允许客户通过他们的WEB浏览器购买货物并用信用卡结帐。这种商务系统使传统的商业方式彻底改变,使零库存的商业理念成为现实,大大节省了资源。图书作为一种实时性很强的商品,根据市场需求迅速改变库存可以给商家和客户带来双赢,所以网络书店的开发显得非常必要和紧迫。
书店不外乎是展示、销售出版物的零售点,除了买卖书籍外,与其它销售通路并无不同。从这样的角度来看,网络书店的基本功能也是如此,不过是出版品另一种型态的宣传或销售通路,甚至是传统店面的辅助。所谓的「网络书店」,除了一般的电子商务功能外,还包括了下列的几项服务:新书展示、流行书籍显示、书籍检索,使商家的服务满意度增加。最重要的是在客户满意的同时也为企业大大的节约金钱,时间和资源,并对整个行业的商业运作产生重要的影响。
网络书店是IT(Information Technology信息技术)应用于商业活动的一个典型产物,其在电子商务领域也有成功的实例,使得我们有足够的经验得以借鉴;而且网络书店是“麻雀虽小,但五脏具全” 。我们实现网络书店基于J2EE规范(specification),采用J2EE推荐(Recommanded)的实现技术,并且应用了开放源码(Open Source)的实现了MVC(Mode-View-Controller)模式的web层框架struts。在开发的过程中遵循软件工程的思想,依据RUP理论,应用UML指导开发。所以网络书店系统对于帮助我们理解J2EE规范、MVC模式理论精髓、JSP技术、servlet技术、struts框架以及提高我们应用Rational Rose进行UML建模都有非常深远的意义。
1.2 网络书店的目的、内容及作者的主要贡献
网络书店的开发初衷是为了迎合电子商务这个社会大前提,一方面使书商实现零库存、以需求决定采购和方便快捷的给客户提供服务;另一方面给客户提供了一个方便的检索平台,客户也可以根据图书评论决定自己的选购。网络书店的最终目的是使书商和客户得到双赢。
网络书店严格遵守J2EE规范,采用J2EE标准的实现技术进行开发,整个开发过程以RUP理论作为指导。这些着重培养我们在软件开发中的需求分析、业务分析和实际编码的能力。
网络书店系统设计人员为杨强和王中领,由于遵照RUP,网络书店系统设计的工作流主要包括:a.商业建模(理解待开发系统的组织结构及其商业运作,确保所有参与人员对待开发 系统有共同的认识);b.需求分析定义系统功能及用户界面,使客户了解系统的功能、开发人员了解系统的需求,为项目预算及计划提供基础;c.分析与设计把需求分析的结果转化为实现规格;d.实现定义代码的组织结构、实现代码、单元测试和系统集成;e.测试校验各子系统 的交互与集成,确保所有的需求被正确实现并在系统发布前发现错误;f.发布打包、分发、 安装软件,升级旧系统。杨强负责用例、商业建模,分析及部分编码和部分测试和打包发布工作;王中领负责需求分析、部分编码和测试以及美工的设计等工作。
1.3网络书店系统设计的进度安排
根据RUP,为了能够方便地管理软件开发过程,监控软件开发状态,RUP从时间维上 把软件开发周期划分为四个阶段:a.起始阶段定义最终产品视图、商业模型并确定系统范围;b.演化阶段设计并确定系统的体系结构,制定工作计划及资源要求;c.构造阶段构造产品并继续演进需求、体系结构、计划直至产品提交;d.提交阶段把产品提交给用户使用。
各阶段主要目标:
1. 起始阶段。1).建立项目的软件规模和边界条件,包括运作前景、验收标准以及希望软件中包括和不包括的内容。 2).识别系统的关键用例(也就是将造成重要设计折衷操作的主要部分)。 3).评估整个项目的总体成本和进度(以及对即将进行的精化阶段进行更详细的评估) 4). 评估潜在风险(不可预测性的来源)
5).准备项目的支持环境。
2. 演化阶段。1).确保构架、需求和计划足够稳定,充分减少风险,有预见性地确定完成开发所需的成本和进度。2).处理在构架方面具有重要意义的所有项目风险,建立一个已确定基线的构架。3).建立支持环境。
3. 构造阶段。识别出剩余的用例。每一次迭代开发都针对用例进行分析、设计、编码(如类声明、属性声明、范围声明、函数原型声明和继承的声明等)、测试和集成过程,所得到产品满足项目需求的一个子集。由于细化阶段的软件设计已经完成,这样各项目组可以并发开发。
在代码完成后,要保证其符合标准和设计规则,并要进行质量检查。对于新出现的变化,要通过逆向工具把代码转换为模型,对模型进行修改,再重新产生代码,以保证软件与模型同步。
此阶段要建立类图、交互图和配置图;如一个类具有复杂的生命周期,可绘制状态图;如算法特别复杂,可绘制活动图。
4. 提交阶段。完成最后的软件产品和最后的验收测试,并完成用户文档编制以及用户培训等工作。
| 开始—完成时间 | 备注 |
起始阶段 | 2005.3.1-2005.3.15 | 作为系统的基石,我们花费了足够长的时间,投入了足够多的精力去实现本阶段。本阶段的时间给的很宽裕,可以根据实际情况,减少时间分配。 |
演化阶段 | 2005.3.16-2005.4.5 | 可以适当压缩时间 |
构造阶段 | 2005.4.6-2005.5.30 | 指定严格的里程碑,控制时间分配 |
提交阶段 | 2005.6.1-2005.6.10 | 可适当减少时间 |
注:在安排进度计划的同时,我们制定了各阶段的主要目标,以期指导和评价我们的进展情况,避免陷入“软件危机”的窘境。
2 需求分析
2.1 现状分析
2.1.1 网络书店的概述
目前电子商务蓬勃发展,网络书店作为其代表在现实生活中也有很多成功的例子,比如国外的amazon、台湾的诚品、金石堂和国内的china-pub、当当网图书分站,他们的功能主要集中在给客户提供人性化服务上,例如精品图书推荐、最新图书上架、书籍排行、网友对图书的评论、打折图书和在线销售等。
2.1.2 网络书店存在的问题
首先就其内容而言,有些书店图书种类不够齐全,有些却全而不精,得不偿失。
其次就其实现技术而言,目前动态网站设计技术主要有:利用Perl/C++/Delphi等开发的CGI,两种有名的API-ISAPI/NSAPI,还有ColdFushion,以及最近几年流行起来的3p技术-ASP,PHP,JSP(据Internet上有关网站统计约有近百种); ASP-Active Server Page,由微软公司开发 ,是一个WEB服务器端的开发环境,主要采用脚本语言VBScript(或Javascript / perl等)作为自己的开发语言,可用ODBC或直接驱动法访问Window平台的数据库。PHP-Person Server Page ,是由Rasmus个人创立的一种跨平台的服务器端的嵌入式脚本语言. 它大量地借用C, Java 和 Perl 语言的语法, 并耦合PHP自己的特性,.是一种很有个性的网站开发语言,它支持目前绝大多数数据库。JSP-Java Server Pages , 是Sun公司推出的新一代站点开发语言,Sun 公司除Java 应用程序 和 Java Applet 之外,又创立了JSP,其可以在Servelet和JavaBean的支持下使实现业务逻辑的代码和控制业务流程的代码分离,使得开发更加的快速和有效;并且兼之Java的跨平台特性,使之优点更加明显。可是当前的大多网站采用ASP和PHP技术,ASP的缺点在于不容易去写易理解、可用性好的代码,因为它的代码中夹杂着脚本和HTML,那很难被读懂,至于重用也只能通过剪贴来实现。由于ASP自身的结构, 很难用面向对象的方法编程。虽然可以通过好的编程习惯,就是使用服务端引用或FrontPage 模板,靠封装代码来提高可用性,并且避免重复代码带来的混乱。但即使这样,项目还是难于管理、维护;PHP的缺点在于由于PHP本身存在的一些缺点,使得它不适合应用于大型电子商务站点,而更适合一些小型的商业站点。首先,PHP缺乏规模支持。其次,缺乏多层结构支持。对于大负荷站点,解决方法只有一个:分布计算。数据库、应用逻辑层、表示逻辑层彼此分开,而且同层也可以根据流量分开,组成二维数组。而PHP则缺乏这种支持。还有上面提到过的一点,PHP提供的数据库接口支持不统一,这就使得它不适合运用在电子商务中。
最后就其网页设计风格而言,国外网站偏重于网站的简洁和素雅,缺少色彩支持,显然不符合中国人的欣赏风格;而国内有些网站又太过于突出色彩搭配,使页面给人以很凌乱的感觉,不能达到好的效果。
2.2 设计目标
2.2.1 系统功能设计目标
通过仔细分析和了解各大网络书店的特色,为了全面的满足客户需求,又可以帮助书商更好的进行管理图书,初步拟定系统功能如下:1. 浏览者浏览图书(包括最新图书、热买图书);2. 浏览者注册为书店客户;3. 注册客户购买图书,管理购物车;4. 注册客户可以对图书进行书评;5. 注册用户管理个人信息(包括书评);6. 书店管理员对注册用户进行管理;7. 书店管理员对书店图书进行管理;8. 书店管理员对书评进行管理;9. 书店管理员对定单进行管理;10. 订单处理系统对订单进行处理;
具体细节见以下活动图:
2.2.2 系统性能实现目标
经过对几种流行的实现技术的优缺点比较,再结合系统自身的功能需要,我们决定采用J2EE标准中的JSP技术实现本系统的开发。
首先,系统具有跨平台性,UNIX服务器的性能更加优良。JSP作为Java平台的一部分,其拥有Java程序设计语言“一次编写,各处执行”的特点。并且随着越来越多的供货商将JSP支持加入到他们的产品中,您可以使用自己所选择的服务器和工具,修改工具或服务器并不影响目前的应用。加之有很多性能良好的免费web服务器支持,也减少了书商的投资金额和风险。
其次,系统开发职责的高度分离和代码的可重用性。使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者小脚本来产生页面上的动态内容。产生内容的逻辑被封装在标识和JavaBeans群组件中,并且捆绑在小脚本中,所有的脚本在服务器端执行。将核心逻辑封装在标识和Beans中,那么其它人,如Web管理人员和页面设计者,能够编辑和使用JSP页面,而不影响内容的产生。在服务器端,JSP引擎解释JSP标识,产生所请求的内容(例如,通过存取JavaBeans群组件,使用JDBC技术存取数据库),并且将结果以HTML(或者XML)页面的形式发送回浏览器。这有助于作者保护自己的代码,而又保证任何基于HTML的Web浏览器的完全可用性。绝大多数JSP页面依赖于可重用且跨平台的组件(如:JavaBeans或者Enterprise JavaBeans)来执行应用程序所要求的更为复杂的处理。开发人员能够共享和交换执行普通操作的组件,或者使得这些组件为更多的使用者或者用户团体所使用。基于组件的方法加速了总体开发过程,并且使得各种群组织在他们现有的技能和优化结果的开发努力中得到平衡。
再次,系统优良的运行速度和安全性。作为实时的服务系统,其对运行速度的要求自然很高,为了提高运行速度,在业务逻辑层对数据库层的访问过程中采用数据库连接池来减少连接数据库对系统性能的损失。由于JSP页面的内置脚本语言是基于Java程序设计语言的,而且所有的JSP页面都被编译成为Java Servlet,JSP页面就具有Java技术的所有好处,包括健壮的存储管理和安全性。
最后,系统的可配置性。J2EE标准和XML语言紧密结合,增强了其系统的可配置性,WEB应用本身通过 web.xml 将各部分粘合在一起,web层框架struts的流程控制通过struts-config.xml来实现,页面的可重用和页面各部分组合通过tiles-defs.xml实现。
2.3 平台选择
2.3.1 操作平台的选择
本着界面友善、易操作和成本低廉的原则我们选择Windows XP。
2.3.2 Web服务器软件的选择
由于电子商务网站的特殊性,考虑到1. 系统的可扩展性和安全性;2. 系统的运行速度;3. 服务器的升级和更换等方面,所以采用免费的、性能卓越的、稳定的和版本升级及时的Apache组织的Apache服务器+Tomcat服务器。
Apache的特点是简单、速度快、性能稳定,并可做代理服务器来使用,并可以可以支持SSL技术,支持多个虚拟主机。Tomcat是Sun和Apache合作做出来的JSPServer,支持Servlet 2.4 and JavaServer Pages 2.0等版本。Apache +Tomcat优势更加明显,Apache处理静态页面,Tomcat处理JSP动态页面。
2.3.3 数据库服务器选择
MS SQL Server2000作为一个成熟的产品,承袭了微软公司一贯的易用性特点,对关系型数据库的特性也都一一实现,是一个理想的选择。
2.3.4 建模工具的选择
建模工具使用Rational公司的Rational ROSE 2002企业版,其包括了一体化建模语言(UML),OOSE及OMT,最主要的是可以可视化的进行快速开发。
2.3.5 集成开发环境工具和测试工具的选择
Java的集成开发环境很多,我们选择在程序员中口碑很好而且非常轻量的免费IDE—Eclipse3.0和MyEclipse3.8插件,测试工具采用免费的单元测试工具JUnit和Rational 公司ROSE2002。
3 数据库设计
3.1 数据库设计
一个成功的管理软件,数据库设计的好坏是一个关键。本系统采用以面向对象编程语言Java为基础的JSP技术,更应该注意到对面向对象的支持。
数据库的设计思想为:1. 数据库结构清晰,便于实现OOP ;由于实现了应用模块对象对数据库对象的完全映射,数据库逻辑模型自然且直接地模拟现实世界的实体关系。2. 数据库对象具有独立性,便于维护;除了数据库表对象与应用模块对象一一对应外,在逻辑对象模型中我们没有设计继承等泛化关系,表类间的关系比较简单,给以后数据库日常维护工作带来便利。3. 需求变更时程序与数据库重用率高,修改少;在映射应用对象时,除关系映射规范化后可能出现一对多的表映射外,大多数应用对象与表对象是一一对应的。
3.2 数据表设计
数据表和各字段的设计思想遵循:1. 命名的规范。由于不同的数据库产品对对象的命名有不同的要求,因此,数据库中的各种对象的命名、后台程序的代码编写应采用大小写敏感的形式,各种对象命名长度不要超过30个字符,这样便于应用系统适应不同的数据库平台。2. 数据的一致性和完整性。为了保证数据库的一致性和完整性,设计人员往往会设计过多的表间关联(Relation),尽可能的降低数据的冗余。 3. 采用有意义的字段名4. 采用前缀命名6. 使用角色实体定义属于某类别的列[字段]
根据对系统问题域的详细分析,抽象出实体类User、Book、Indent、IndentList、Review和BookList,遵循上面的设计思想,网络书店的数据表及各表之间的关系如下:
书店图书种类表My_BookClass (Id,ClassName) [对应于BookClass类]
id(为图书种类标识)ClassName(图书种类名称);网络书店的图书种类通过添加、删除该表达到预期效果。[表的Schema如图3-1:]
图书信息表My_Book (Id,BookName,BookClass,RegTime,img_name,img_path,Author,Publish,BookNo,Content,Prince,Amount,Leav_number,reviewcount,IsRecommanded,RegTime)[对应于BookClass类]
BookName(图书名称)BookClass(图书分类)RegTime(图书登记时间)img_name(图书图片名称)img_path(图书图片存储路径)Author(图书作者)Publish(图书出版社)BookNo(图书编号)Content(图书简介)Prince(图书价格)Amount(图书库存)Leav_number(图书剩余量)reviewcount(图书书评数)IsRecommanded(图书是否推荐标识)[表的Schema如图3-1:]
图书信息表中除了基本信息外,还包括图书图片的存储路径,主要是为了让客户对图书有一个感官上的认识;然后还有是否推荐标识,是书店的特色,将会根据市场反映定期推荐一部分很受好评的图书。
订单信息My_IndentList (Id,IdentNo,BookNo,Amount) [对应于IndentList类]
是图书和订单的关联表,IdentNo(订单Id)BookNo(图书Id)Amount(购买数量)[表的Schema如图3-1:]
书店管理员信息表My_BookAdminuser (AdminUser,AdminPass)[对应于BookClass类]
进行图书和客户信息管理的书商信息,用于登陆时的身份验证。AdminUser(管理员用户名)AdminPass(管理员密码)[表的Schema如图3-1:]
订单条目表My_Indent (Id, IdentNo, UserId, SubmitTime, ConsignmentTime, TotalPrice, content, IPAdress, IsPayoff, IsSales) [对应于Indent类]
IdentNo(订单号)UserId(用户号)SubmitTime(订单提交时间) ConsignmentTime(订单确认时间) TotalPrice(价格总数)content(订单附加内容)IPAdress(下单时的IP) IsPayoff(是否已付款) IsSales(是否交货)[表的Schema如图3-1:]
订单条目表存储本系统的核心数据,他与订单表和用户表有外键约束关系,通过IsPayoff和IsSales这两个字段对订单状态进行改变。
书店客户信息表My_Users (Id, UserName, PassWord, Names, Sex, Address, Phone, Post, Email, RegTime, RegIpAddress) [对应于ShopUser类]
UserName(用户名)PassWord(用户登陆密码)Names(用户真实姓名) Sex(用户性别)Address(用户送货地址) Phone(用户的联系电话)Post(用户邮编)Email(用户电子邮箱)RegTime(用户注册时间) RegIpAddress(用户注册时IP)[表的Schema如图3-1:]
用户的联系方式必须认真填写,一方面确定图书一定送达客户,另一方面确定客户真实身份。其中系统会根据用户提供的电子邮件在其确认订单以后发送订单详细情况予以确认,另一方面为防止客户忘记登录本网站的密码,将电子邮件作为其获取密码的依据和传送密码的媒介。
图书评论表Review(Id, BookId, UserName, content, WriteTime) [对应于Review类]
BookId(评论的图书标识)UserName(进行书评的客户Id) content(书评的具体内容)WriteTime(书写书评的具体时间) [表的Schema如图3-1:]
各表的Id均为数据表的主键,各表之间的约束关系为:My_BookClass中Id 为 My_Book中BookClass的外键; review中bookid受约束于 My_Book表中的id字段; My_book 中的ID约束My_IndentList中的BookNo; My_IndentList中identNo受约束于 My_Indent的identNo; My_Indent 的UserId 受约束于My_Users的Id ;review UserName 受约束于My_Users中的Id 。
其中一对多关系,它是数据库中最普通的关系类型。这种关系双被称为是父表与子表关系或主表与分表关系。
多对多关系,就是第一张表的每一行可对应第二张表的许多行。
一对一的关系,就是将一个表中的行与另一表中的行连接来。
将理论结合实际,该系统各表之间具体的关系如如图3-1:
4系统实现技术
4.1 系统架构设计
4.1.1 系统架构概论
构架(Architecture,愿意为建筑学设计和建筑物建造的艺术与科学): 在RUP中的定义:软件系统的构架(在某一给定点)是指系统重要构件的组织或结构,这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互;《软件构架实践》中的定义:某个软件或者计算系统的软件构架即组成该系统的一个或者多个结构,他们组成软件的各个部分,形成这些组件的外部可见属性及相互 间的联系;IEEE 1471-2000中的定义:the fundamental organization of a system emboided in its components,their relationships to each other,and to the enviroment and the principles guiding its design and evolution,构架是系统在其所处环境中的最高层次的概念。软件系统的构架是通过接口交互的重要构件(在特定时间点)的组织或结构,这些构件又由一 些更小的构件和接口组成。(“构架”可以作为名词,也可作为动词,作为动词的“构架”相当于“构架设计”)
结构:软件构架是多种结构的体现,结构是系统构架从不同角度观察所产生的视图。就像建筑物的结构会随着观察动机和出发点的不同而有多种含义一样,软件构架 也表现为多种结构。常见的软件结构有:模块结构、逻辑或概念结构、进程或协调结构、物理结构、使用结构、调用结构、数据流、控制流、类结构等等。
构架的全部内容就是复杂性管理:将解决方案划分为多个小的组成部分,再将这些小的部分结合起来,构成一个更大的、更加统一的结构。
4.1.2 本系统架构考虑的因素
1、程序的运行时结构方面的考虑:
1) 需求的符合性:正确性、完整性;功能性需求、非功能性需求;2) 总体性能(内存管理、数据库组织和内容、非数据库信息、任务并行性、网络多人操作、关键算法、与网络、硬件和其他系统接口对性能的影响);3) 运行可管理性:便于控制系统运行、监视系统状态、错误处理;模块间通信的简单性;与可维护性不同;4) 与其他系统接口兼容性;5) 与网络、硬件接口兼容性及性能;6) 系统安全性;7) 系统可靠性;8) 业务流程的可调整性;9) 业务信息的可调整性;10) 使用方便性11)构架样式的一致性
注:运行时负载均衡可以从系统性能、系统可靠性方面考虑。
2、源代码的组织结构方面的考虑:
1)开发可管理性:便于人员分工(模块独立性、开发工作的负载均衡、进度安排优化、预防人员流动对开发的影响)、利于配置管理、大小的合理性与适度复杂性;2)可维护性:与运行可管理性不同;3)可扩充性:系统方案的升级、扩容、扩充性能;4)可移植性:不同客户端、应用服务器、数据库管理系统;5)需求的符合性(源代码的组织结构方面的考虑)。
4.1.3 本系统软件的功能结构模型
作为一个纯粹的电子商务网站,除了实现大部分特征功能外,还加入了一些更人性化的功能,具体功能结构如下图4-1所示(其中人棒形表示使用该系统的参与者,它以是现实世界的人,也可以是逻辑世界的一个外部系统;椭圆形表示该系统为参与者提供的功能,它下面的名称是对某一相对功能的描述和标识。整个椭圆代表的功能组成了系统的功能集。)
特别说明:商店客户是浏览者的特殊化,他们之间是泛化关系,浏览者在本书店填写正确的个人信息后方能成为商店客户,然后才能进行购书等活动。
4.1.4系统构架
下面将把系统中所用的类根据高内聚、低耦合的原理划分到几个包中,并且每个类有清晰的且严格定义的目的和职责,各组类的关系也很明确。
各包情况如下:
包po:Book类、 BookClass类、Indent类、 IndentList类、Review类、ShopUser类
包bo:ReviewBO类、AttentionBO类、BookClassList类、PopBO类、PurchaseBO类、UpLoadBO类、UserBO类、BooksBO类
包action:AddBookAction类、AddReviewAction类、RegisterAction类
包form:AddBookForm类、AddReviewForm类、RegForm类
依赖指的是如果在一个关系中指定的其中一个实体不存在,那么另一个实体也没有存在的意义。当依赖型实体(子类型)的各个实体依赖于超类型中对应父实体存在时,则一个实体类型依赖于另一个实体类型。
该系统中各包之间的关系如下图4-2所示(其中AdminJSP和UserJSP包是JSP页面,AdminJSP包是前端显示系统为用户提供的功能,UserJSP包是后台管理员对书店进行管理的页面合集。体现在物理存储上就是一个文件路径,在该系统中,AdminJSP的JSP文件应在根目录下的manage下,UserJSP的JSP文件直接放在根目录下。):
4.2 系统各部分的实现方法
4.2.1 WEB层的实现方法
JSP技术无疑是优秀的,我们选择它进行web层开发。JSP有两种比较典型的开发模式:Model1、Model2。
Model1把所有的代码都放在JSP中或抽取部分业务逻辑代码放于JavaBean中。这样做的好处是简单、开发快、易于 实现,对于小型系统还可以接受。缺点是JSP页面充斥着用<%%>标示的Java代码段,使得整个JSP页面显得非常混乱,可读性差,难以维护,代码重用性低,还必需另外添加用于控制业务流程的代码。
在Model2中,它使用Servlet作为整个架构的控制器,负责完成接受请求,根据请求改变模型中的数据;在数据改变后,通知相关的视图进行刷新(View由JSP组成)。这样做的好处在于:用JSP网页专门用于表现数据而无需进行其他操作,使得JSP页面没有或只含很少的Java代码。使得页面清晰,提高了可读性,便于维护。虽然Model2在一定程度上实现了MVC,但是它的应用并不尽如人意。一个比较突出的问题是Model2 容易使系统出现多个Controller,并且对页面导航的处理比较复杂。
认识到这一点,我们决定采用Jakarta 的Struts框架,它是是一个由Apache软件基金会发起的一个开源项目,它是Model-View-Controller (MVC)设计模式服务器端的Java实现。Jakarta Struts 工程最先是由Craig McClanahan在2000年5月创建,但从那以后就完全由一些开源组织接管。Struts 工程设计的意图是为JSP的Web应用开发提供一个易于把显示层和事务层分离的开源框架,在这个框架支持下很容易实现JSP系统的Model2开发模式。Struts框架具有可靠性高、适应性强、开发和维护时间短和易于维护等优点。它的框架组成如下:
组件名 | 功能描述 |
ActionServlet | 控制器。 |
ActionClass | 包含事务逻辑。 |
ActionForm | 显示模块数据。 |
ActionMapping | 帮助控制器将请求映射到操作。 |
ActionForward | 用来指示操作转移的对象。 |
ActionError | 用来存储和回收错误。 |
Struts标记库 | 可以减轻开发显示层次的工作。 |
诚然struts是优秀的,可也存在下列问题:1. tag lib学习周期长,扩展并不容易,远低于用脚本或者xslt的开发效率。 在页面引入tag以后,其实某种意义上逻辑更加混乱,如果没有好的可视化集成环境的支持,开发效率低、维护成本也高。对于美工要求高的页面,美工根本没办法动手。2. 配置文件。如果没有整合的工具,维护是个问题。1.1中引入的commmon validation,把维护工作进一步增加了。 开发工作中有可能很多时间都会花在解决这些冲突上。3。层面太多,做小应用不适合,远不如jsp+bean的方式简洁快速。 做大应用的话,因为他只是一个表现层的东西,不能单纯的解决问题。 要和复杂的框架结合需要费功夫。
结合以上所述,我们系统的WEB层采用struts+jsp+servlet进行协同开发。
简化页面设计,我们采用的是struts的Tiles技术,它由tile-def.xml,负责调用配置的***.jsp和网页公用部分的***.jsp 组成。
tiles-def.xml:
<definition name="index-definition" path="/public/layout.jsp">
<put name="top" value="top.jsp"/>
<put name="pupbook" value="pupbook.jsp"/>
<put name="sidebar" value="side1.jsp"/>
<put name="content" value="newbook.jsp"/>
<put name="logon" value="logon.jsp"/>
<put name="selllist" value="selllist.jsp"/>
<put name="booter" value="booter.jsp"/>
</definition>
负责调用配置的***.jsp
<tiles:insert definition="userinfo-definition"/>
网页公用部分的***.jsp和普通jsp页面一样。
网页的风格,一方面便于管理,一方面使页面风格保持一致,我们应用CSS技术对网页风格进行优化:
default.css(对超连接的显示颜色及访问后的显示颜色;页面正文的字体和大小以及正文中应用表格后的字体颜色和大小进行统一规定)
A:link { COLOR: #003399; TEXT-DECORATION: none } A:visited { COLOR: #336699; TEXT-DECORATION: none } A:active { TEXT-DECORATION: none } A:hover { COLOR: #000000; TEXT-DECORATION: underline } .bookname { FONT-WEIGHT: bolder } TD { FONT-SIZE: 12px; COLOR: #003399; LINE-HEIGHT: 18px } .author { COLOR: lightgrey } .oldprice { COLOR: firebrick; TEXT-DECORATION: line-through } .price { COLOR: firebrick } .datail { COLOR: black } .title { FONT-WEIGHT: bolder; FONT-SIZE: 12px; LINE-HEIGHT: 16px } .title1 { FONT-WEIGHT: bolder; FONT-SIZE: 12px; COLOR: white; LINE-HEIGHT: 16px } .font1 { FONT-SIZE: 12px; LINE-HEIGHT: 18px } .font2 { FONT-SIZE: 12px; COLOR: #3a6ea5 } .font3 { FONT-WEIGHT: bolder; FONT-SIZE: 20px; COLOR: darkslategray; LINE-HEIGHT: 24px } .fenlei { BACKGROUND-COLOR: #a0caf0 } .zhuti { BACKGROUND-COLOR: #3a6ea5 } .paihang { BACKGROUND-COLOR: #f9f6e6 } .left { BACKGROUND-COLOR: #f5fafe } .tdnormal { BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BACKGROUND-COLOR: #93bee2 }a.dada:visited {font-size:15px;color: #FFFFFF; text-decoration: none; font-weight: bold}a.dada:link {font-size:15px;color: #FFFFFF; text-decoration: none; font-weight: bold}a.dada:hover {font-size:15px;color: #000000; text-decoration: none; font-weight: bold}
.namedd2{
FONT: bold 12px/14px "Times New Roman", "Times", "serif";
COLOR: #000000
}
4.2.2 控制类和业务逻辑层的实现方法
前面说过struts在程序流程控制上的解决发法很优秀,我们采用struts的ActionServlet处理业务流程的转向。业务逻辑层采用标准的JavaBean组件,它接受显示层的信息封装对其请求进行商业逻辑处理。
(1). 控制类及业务逻辑处理主要设计封装用户提交信息的类ActionForm、包装业务逻辑类的类Action、配置文件struts-config.xml、业务逻辑类***BO.java。
配置文件struts-config.xml
<form-beans >
<form-bean name="regForm" type="org.nwsuaf.struts.form.RegForm" />
……
</form-beans>
<action-mappings >
<action
attribute="regForm"
input="/reg.jsp"
name="regForm"
path="/register"
scope="request"
type="org.nwsuaf.struts.action.RegisterAction"
validate="true">
<forward
name="success"
path="/userinfo.jsp"
contextRelative="true" />
</action>
……
</action-mappings>
封装用户提交信息的类ActionForm只是一般的JavaBean类;
包装业务逻辑类的类Action(其中ReviewBO和login都是业务逻辑类)
ReviewBO rb=new ReviewBO();
Review review=new Review();
HttpSession session=null;
login alogin=new login();
alogin.setUsername(addreviewForm.getUsername());
alogin.setPasswd(addreviewForm.getPassword());
if(!alogin.excute()){
return mapping.findForward("login");
}
else{
review.load(addreviewForm.getBookid(),addreviewForm.getUsername(),addreviewForm.getContent());
(2). ***BO.java是具体的业务逻辑类,它是衔接web层和数据库层的纽带,为了提高重用性,我们将常用数据库的操作方法集放在一个抽象类中(DataBase)。其他凡是涉及到数据库操作的业务逻辑类都要继承该父类。例如:
public class PopBO extends DataBase{类属性和行为}
为了提高书店的服务质量和减少书店的成交失败率,我们采用了电子邮件确认的方式。在发送邮件类中我们采用了sun公司的JavaMail包,又考虑到系统的可配置性和通用性,我们采用property文件来存储邮件发送者信息解决这一问题,具体代码如下:
SendMail.java
public boolean sendMail(){
try{
Properties prop =new Properties();
try{
InputStream is=getClass().getResourceAsStream("mail.properties");
prop.load(is);
if(is!=null)is.close();
}catch(IOException e){
System.out.println("[DbConncetion]打开文件时出现错误");
}
//从property文件中读取propetty
String smtp=prop.getProperty("smtp");
String adminEmail=prop.getProperty("email");
String username=prop.getProperty("username");
String password=prop.getProperty("password");
System.out.println(smtp+username+password);
Properties p=System.getProperties();
p.put("mail.smtp.host",smtp);
p.put("mail.smtp.auth","true");
Session session=Session.getDefaultInstance(p,new Email_ca(username,password));
MimeMessage msg=new MimeMessage(session);
msg.setSentDate(new Date());
InternetAddress from=new InternetAddress(adminEmail);
msg.setFrom(from);
InternetAddress[] address = {
new InternetAddress(tomail)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject(this.subject);
msg.setText(this.content);
msg.setHeader("Content_Type","text/html");
Transport.send(msg);
return true;
}catch(AddressException addr_e){
System.out.println(addr_e.getMessage());
return false;
}catch(MessagingException msg_e){
System.out.println(msg_e.getMessage());
return false;
}
}
存储邮件信息的mail.properties:
smtp=smtp.163.com
email=用户名@163.com
username=用户名
password=密码
(3). 显示查询数据库信息时,考虑到页面整洁,我们采用数据库的TOP函数来达到分页目的,其具体SQL代码如下:
sqlStr=”select top “+pageSize+” a.id,a.bookname,a.bookclass,a.img_path,b.classname, a.author,a.publish,a.bookno,a.content,a.prince,a.amount,a.Leav_number,a.regtimefrom My_book a,My_bookclass b where a.Bookclass = b.Id ";
if (!classid.equals("") && keyword.equals("") ){ //如果类别不为空,非查询
if (page == 1){
sqlStr = sqlStr + " and a.bookclass='" + classid + "' order by a.Id desc";
} else if((recordCount-pageSize * page)< 0){
sqlStr = sqlStr + " and a.bookclass='" + classid + "' and a.Id not in ( select TOP 0 Id from My_book order by Id ) and a.Id in " +"(select TOP " + (0+rscount) + " Id from My_book ORDER BY Id ) order by a.Id desc";
}else {
sqlStr = sqlStr + " and a.bookclass='" + classid + "' and a.Id not in ( select TOP " + (recordCount-pageSize * page ) +" Id from My_book order by Id ) and a.Id in " +"(select TOP " + (recordCount - pageSize * (page-1)) + " Id from My_book ORDER BY Id ) order by a.Id desc";
}
(3). 图书销售排行通过MS SQL2000提供的DateDiff()函数计算日期插值和数量比来实现,具体的SQL实现语句如下:
String sqlStr="select (Amount-Leav_number)/DateDiff(y,RegTime-1,getdate()) as pop,a.id,
a.bookname,a.bookclass,a.img_path,a.author,a.publish,a.bookno,a.content,a.prince,a.amount,a.Leav_number,a.regtime from My_Book a order by pop desc";
(4). 输出日志,是为了监视代码运行中代码的变化情况、跟踪代码运行时轨迹和便于发现调试代码的逻辑错误。
我们通过一个servlet程序操纵有关Log4J的工作,然后在web.xml中设定该servlet的装载优先级,使其在Web程序初始化时就运作,达到完全输出日志的目的。
Log4jInit.java
public void init() throws ServletException {
String prefix = getServletContext().getRealPath("/");
String file = getServletConfig().getInitParameter("log4j-config-file");
System.out.println("................log4j start");
// 从Servlet参数读取log4j的配置文件
if (file != null) {
PropertyConfigurator.configure(prefix + file);
}
}
web.xml(关于该servlet类的配置)
<servlet>
<servlet-name>log4jinit</servlet-name>
<servlet-class>org.nwsuaf.util.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-config-file </param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
log4j.properties(初始化Log4J工作的方式)
log4j.category.org.zblog=ERROR,A1
log4j.category.org.zblog=INFO,A2
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target=System.out
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
log4j.appender.A2=org.apache.log4j.RollingFileAppender
log4j.appender.A2.File=D:/Tomcat 5.0/webapps/book/book.html
log4j.appender.A2.MaxFileSize=500KB
log4j.appender.A2.MaxBackupIndex=1
log4j.appender.A2.layout=org.apache.log4j.HTMLLayout
4.2.3 数据库层(持久层)的实现方法
本系统采用OO(面向对象)的思想进行开发,必须实现关系(数据库)和对象之间的对应(O/R Mapping),虽然现在有很多的O/R Mapping工具,可因为时间关系,我们采用JavaBean来实现两者间的映射(Mapping)。
我们用面向对象的思想,将连接数据库代码抽象为一个数据库连接管理类,为了方便把我们的系统移植到任何机器上和任何关系型数据库产品上,我们采用property文件存储连接数据库的有关信息,通过该管理类读取该类实现我们的目标,具体代码如下:
DBConnectionManager.java
public Connection getConnection() {
Properties prop =new Properties();
try{
InputStream is=getClass().getResourceAsStream("db.properties");
prop.load(is);
if(is!=null)is.close();
}catch(IOException e){
System.out.println("[DbConncetion]打开文件时出现错误");
}
try {
Class.forName(driverName);
return DriverManager.getConnection(url, user, password);
}
catch (Exception e) {
System.out.print("获取conn失败");
return null;
}
}
db.properties
driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
url=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=book
user=sa
password=
以上为我们的测试写法,我们的数据库是MS SQL2000,用户名为sa,密码为空,可以根据实际情况改写以上信息,而不用重新编译管理类,大大提高了系统代码的可维护性。
4.3程序流程
附:部分页面的逻辑流程
5 系统测试与评价
程序和系统的测试及调试的目的是发现程序和系统中可能存在的错误并及时予纠正。系统测试主要有单元测试和功能测试。单元测试告诉开发者代码使事情正确的被执行,而功能测试所说的则是代码在正确地发挥功效。单元测试是从开发者角度编写的。它确保类的每个特定方法成功执行一系列特定的任务。每个测试都要保证对于给定的一个已知的输入应该得到所期望的输出。功能测试是丛用户的角度来编写的,这些测试保证系统能够按照用户所期望的那样去运行。
5.1 测试环境介绍
5.1.1 测试工具JUnit的介绍
JUnit平台的设计架构是采用了命令(Command)和复合(Composite)两种设计模式(Design Pattern)做为关键的组成架构。在JUnit平台中的核心类别是TestCase,而每一个TestCase代表着一个命令对象。TestCase 包含数个test method,用来测试被测类别内public method的产出对象与预期的结果是否相同。在JUnit平台内有提供数种用来协助比对的assert method。
JUnit平台里还有另一个核心类别是TestSuite,而每一个TestSuite代表着一个复合的对象。一个TestSuite可以由数个 TestCase或是数个TestSuite组成,因此可以根据测试的需求,拼凑出多个的TestSuite。
5.1.2 测试环境介绍
本系统是web应用,除了对处理业务逻辑的JavaBean进行单元测试外,也对web程序进行了严格的功能和性能测试 。
用于测试的环境是连网下的计算机,单元测试的JUnit依附于IDE工具Eclipse,为其提供GUI,方便测试。
5.2 实例测试
本次从界面、程序代码(单元测试)和功能(包括性能)三方面对系统进行了测试,具体内容如下所述。
5.2.1 界面测试
界面测试就是通过界面设计的准则对系统的界面进行评审和修改。主要依据以下几个原则:1. 直观性。 用户界面是否洁净,不唐突,不拥挤。界面不应该为用户制造障碍,所需功能或者期待的响应应该明显,并在预期出现的地方。界面组织和布局合理吗?是否允许用户轻松地从一个功能转到另一个功能?下一步做什么明显吗?任何时刻都可以决定放弃或者退回,退出吗?输入得到承认了吗?菜单或者窗口是否深藏不露?有多余功能吗?软件整体抑或局部是否做得太多?是否有太多特性把工作复杂化了?是否感到信息太庞杂?如果其他所有努力失败,帮助系统真能帮忙吗?2. 一致性。快速键和菜单选项,在Windows 中按F1键总是得到帮助信息、术语和命令。整个软件使用同样的术语吗?特性命名一致吗? 软件是否一直面向同一级别用户?带有花哨用户界面的趣味贺卡程序不应该显示泄露技术机密的错误提示信息。 按钮位置和等价的按键。大家是否注意到对话框有OK按钮和Cancle按钮时,OK按钮总是在上方或者左方,而Cancle按钮总是在下方或右方?同样原因,Cancle按钮的等价按键通常是Esc,而选中按钮的等价按钮通常是Enter,保持一致。 3. 灵活性。状态跳转、灵活的软件实现同一任务有多种选择方式, 状态终止和跳过,具有容错处理能力。数据输入和输出.用户希望有多种方法输入数据和查看结果。4. 舒适性。恰当软件外观和感觉应该与所做的工作和使用者相符。错误处理程序应该在用户执行严重错误的操作之前提出警告,并允许用户恢复由于错误操作导致丢失的数据.如大家认为undo /redo是当然的。
5.2.2程序代码(单元测试)
本系统进行了仔细的测试,在系统各个类的编写中就开始测试,这样有助于尽早地发现系统中的错误,以减少在后面集成测试中出 现问题的机率,也减少在集成测试中的发现问题后修改源程序的难度。此时的测试主要是用到一些测试数据,测试数据除采用正常数据外,还包括了一些异常数据和临界数据,用他们来考验程序逻辑上的正确性。测试数据是经过精心挑选的,使程序和模块中的每一条语句都能得到执行,即能够测试程序中的任一逻辑通路。
在Eclipse下使用JUnit进行测试的操作步骤如下:
1. 建立一个junit.framework.TestCase的实例。2. 定义一些以“test”开头的无返回方法。一个测试类包含这些:TestCase的子类和一个叫做test***()的方法。这个方法调用了assertEquals()函数,它用来比较我们预期的值和由***()返回的值。Main()方法用来运行测试和显示输出的。JUnit的TestRunner处理测试,提供基于图像和文本的输出表现形式。我们使用基于文本的版本,因为 Eclipse支持它,且也适合我们。当开始运行后,基于文本的版本测试会以文本形式输出,Eclipse会把这些输出自动变成图像界面的输出。
本系统的发送邮件Bean在Eclipse下使用JUnit的实际操作:
1. 测试代码。
public class SendEmailTest extends TestCase {
public SendEmailTest( String name) {
super(name);
}
public void testSend() {
SendEmail se = new SendEmail();
se.setTomail("yq76034150@163.com");
se.setContent("yq76034150");
se.setSubject("yq76034150");
assertEquals(true, se.sendMail());
}
public static void main(String[] args) {
junit.textui.TestRunner.run( SendEmailTest.class);
}
}
1. 测试结果。
和预期相同时的结果,如下图5-1:
和预期不相同时的结果:
5.2.3功能和性能测试
功能测试基于我们的需求分析,在面向对象的程序设计中,一个优秀的设计必须是系统用例决定测试用例。我们的测试用例遵循以下原则设计:1. 软件或项目的名称 2. 软件或项目的版本(内部版本号)3. 功能模块名,测试用例的简单描述,即该用例执行的目的或方法 4. 测试用例的参考信息(便于跟踪和参考)5. 本测试用例与其他测试用例间的依赖关系 6. 本用例的前置条件,即执行本用例必须要满足的条件,如对数据库的访问权限 用例的编号(ID),如可以是 软件名称简写-功能块简写-NO.。7. 步骤号、操作步骤描述、测试数据描述 8. 预期结果(这是最重要的)和实际结果(如果有BUG管理工具,这条可以省略) 9. 开发人员(必须有)和测试人员(可有可无)10. 测试执行日期。
给出一个测试用例的模板:
项目/软件 | 网络书店 | 程序版本 | **** |
|
|
功能模块名 | Login | 编制人 | 杨强 |
|
|
用例编号 | Book_TestLogin | 编制时间 | 2005.5.15 |
|
|
相关的用例 | 无 |
|
|
|
|
功能特性 | 用户身份验证 |
|
|
|
|
测试目的 | 验证是否输入合法的信息,允许合法登陆,阻止非法登陆 | ||||
预置条件 | 无 | 特殊规程说明 | **** |
|
|
参考信息 | 需求说明中关于“登陆”的说明 测试数据 用户名=yq 密码=yq | ||||
操作步骤 | 操作描述 | 数 据 | 期望结果 | 实际结果 | 测试状态 |
1 | 输入用户名称,按“登陆”按钮。 | 用户名=yq,密码为空 | 密码不能为空 | 密码不能为空 | 成功 |
... | ... | ... | ... | ... | ... |
测试人员
|
| 开发人员 |
| 项目负责人 |
|
同时给出一个具体的功能(用户忘记密码时,通过填写注册时的电子邮件将他的密码发送至他的邮箱)测试代码和结果:
public void setUp() throws Exception{
super.setUp();
//指明web应用的根
File context = new File("d://tomcat 5.0//webapps//book");
setContextDirectory(context);
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testSuccessfulLogin() {
addRequestParameter("email","yq76034150@sohu.com");
setRequestPathInfo("/getPassword");
actionPerform();
verifyForward("success");
verifyForwardPath("/content/successcontent.jsp");
verifyNoActionErrors();
}
public void testFailedLogin() {
setRequestPathInfo("/getPassword");
actionPerform();
verifyInputForward();
verifyActionErrors(new String[] {"error.email.required"});
}
public static void main(String[] args) {
junit.textui.TestRunner.run(GetPasswordActionTest.class);
}
这段程序测试了邮件地址填写正确时和不填与预料的情况是否相等的情况。和预期相同时的显示结果:
不相同时的结果:
性能测试从客户端和服务器端两方面进行测试。应用在客户端性能测试的目的是考察客户端应用的性能,测试的入口是客户端。它主要包括并发性能测试、疲劳强度测试、大数据量测试和速度测试等,其中并发性能测试是重点。对于应用在服务器上性能的测试,可以采用工具监控,也可以使用系统本身的监控命令。实施测试的目的是实现服务器设备、服务器操作系统、数据库系统、应用在服务器上性能的全面监控,
5.3 评价分析
经过详细周密的测试,界面的颜色庄重素雅,风格大体一致,通过CSS技术统一规定页面风格使之修改也有了很大方便。功能方面也大体完成了系统开发前期的预定目标,并且业务逻辑处理组件的抽象和各组件的关联符合“高内聚、低藕合“的设计思想,使程序的可扩展性和可维护性大大增强。系统严格遵循JSP规范,页面安全措施得当,可惜没有数据库及时备份功能,虽然可以在服务器端进行设置,却增加了系统的使用复杂度。
6 系统实现过程中遇到的问题及解决方法
6.1 系统分析中的问题描述及解决技术
1. 由于本系统是自主立项,没有实际的客户需求,在系统的分析之初,可谓困难重重。幸运的是,网络书店的成功案例很多,而且我们也曾经是网络书店的顾客,所以通过对各大网络书店的功能进行总结,然后加上我们对网络书店的需求共同组成了系统的需求。
2. 由于是首次应用UML进行系统分析,所以一方面要理解系统需求,另一方面又要学习UML和建模工具ROSE的使用,大部分是通过搜索网络资料、研读电子书和用即时通工具请教别人解决的。
6.2 系统实现中的问题描述及解决技术
6.2.1 系统概要设计阶段的问题描述和解决方案
1. 数据库设计遇到的问题:由于表之间的关联关系比较复杂,且采用面向对象的编程语言实现,所以在考虑设计表的ACID和各范式的同时还要考虑到数据表与对象间的平滑映射问题。折中解决方案如下,将图书信息包括图片路径、书评数目、库存数量全部统一在My_Book数据表中;订单和订单条目分做两个表,订单条目作为关联表将用户信息和订单信息联系起来,减少了数据的冗余。
2. 总体设计遇到的问题:如何根据“高内聚、低耦合”的原则将类分组,使各类之间的关系粒度适合,是保证系统具有可扩展性、可维护性、可重用性的关键。解决方法如下:根据软件业的通用划分方法,我们将所有类分组为:PO(持久对象类),用来将数据库表信息映射到对象中来;BO(业务对象类),是系统中处理业务逻辑的类组合。
6.2.2 系统详细设计阶段及编码阶段的问题描述和解决方案
问题编 号 | 问题描述 | 解决方案 |
1 | JSP页面中包含了太多的控制流程代码和业务逻辑代码 | 一部分页面采用struts框架,并将所有的逻辑处理代码独立为JavaBean组件,提高系统的可重用性和可维护性 |
2 | 提高系统的移植性,对数据库连接可进行灵活的配置。 | 采用JAVA提供的properties属性文件将数据库连接所需要的信息分离到一个独立的DB.properties文件中,然后在连接管理类DBConnectionManager中利用JAVA的I/O技术读取连接信息,实现程序的移植性。 |
3 | 由于本系统需要频繁操作数据库,当然大部分页面涉及到数据库连接,所以提高代码的可重用性(同时降低代码冗余)很重要。 | 建立DBConnectionManager.java专门负责连接数据库。各业务类只要调用这个管理类就可以了。 |
4 | 由于本系统需要频繁操作数据库,可能操作某个数据表后马上又要操作,如果每次都重新请求连接,就会大大降低性能,如何才能使系统性能在完成相应功能的提前下还能最少的消耗资源是我们必须解决的问题。 | 数据库连接池是解决这一问题的方法,其采用缓冲原理,来管理和优化程序对数据库的连接和操作请求。我们使用WEB服务器Tomcat自带的数据库连接池功能,一来它的实现方案比较优秀,二来它的配置也比较简单。 |
5 | 由于在图书简介和书评中,可能会出现换行,那么在HTML页面显示和在数据库中存储就有一个格式转换问题,由于他在系统中出现的次数较多,所以应该将其功能抽象分离出来。 | 编写了一个strFormat类,将HTML格式转化为普通格式,将普通格式转换为SQL格式。 |
6 | 图书的展示应该最大化的直观,一个方法就是给图书添加图片信息,这就存在一个图片如何读取的问题,如果将图片内容直接存入数据库,会增大数据库的容量,使数据库性能有所降低,如果存储路径,又会使程序的复杂度增加,如何调和矛盾是一个重要问题。 | 最后经过权衡,选择用存储路径来处理对图片的操作,每次通过获取相对路径的函数来正确定位图片位置。 |
7 | 数据库中图片路径从何而来,不可能让管理员手动添加路径,一则符合我们开发软件提高工作效率的目的,二则手动添加容易出错。 | 采用struts的upload组件,在管理员添加图书时,通过文件选择上传图片并将其存入指定路径,通过getRealPath()函数获取绝对路径,使图片能正确显示。 |
8 | 系统必须提供图书的排行,一来指导用户购书,再则可以给书店提供进书依据。如何才能使排行权威和科学是一个比较难的问题。 | 排行依据单位时间内的售书个数进行排行,具体的实现是采用SQL中的日期函数DiffDate()运算日期差额,再被手术个数相除得到。 |
9 | 系统默认编码为Unicode双字节编码,可我们使用简体中文的GB2312编码,要使中文显示和数据库存储不出现乱码必须在每处进行硬编码,可是涉及中文乱码的地方较多,如何从全局解决中文乱码是个非常棘手的问题。 | 采用J2EE规范中的Servlet的Filter类,并在web程序的配置文件web.xml中设置该servlet的初始权限,以使其进行对所有客户端请求的中文信息编码。 |
10 | 页面里太多相同部分,如何使其分离增强JSP页面的简洁以及使功用部分达到重用也是一个难题。 | 采用JSP的标准标签<jsp:include/>不能最大程度的达到要求,最后采用struts的Tiles对页面布局进行设计,通过tiles-defs.xml对个页面进行组合。 |
特色程序段见附录3 |
6.3 系统测试中的问题描述及解决技术
问题编 号 | 问题描述 | 解决方案 |
1 | 如何在IDE工具Eclipse中使用单元测试工具JUnit | 下载支持JUnit的插件Myeclipse,按照网络资料的步骤完成测试工具的配置。 |
2 | 界面设计不够统一 | 采用CSS(曾叠样式)对页面进行统一设计。 |
3 | 页面提交功能测试比较困难 | 寻求网友帮助,部分采用HttpUnit对页面进行测试 |
特色程序段见附录3 |
7 结束语
三个月的毕业设计,虽说时间不长,可也经历了很多挫折和欣喜,收获颇多,感受也颇多!我的系统是网络书店,这个题目构思的比较早,寒假期间看完了《Enterprise Java with UML中文版》,决定采用UML语言知道系统的开发和设计。最初的想法是web层用struts框架、中间层用Spring框架、持久层(数据库层)用Hibernate框架,可是里面的知识我都是刚刚接触,谈不上了解,最后就以最初的想法开始系统的开发了。可惜最后发现深陷“技术的焦油坑”不可自拔,按照我最初的进度计划,工作进度应该说是严重滞后。不得已,最后我又改变了系统的整体架构,web层用struts和jsp, 中间层用JavaBeans和servlet,持久层也用JavaBeans。令人欣慰的是,最后还是比较好的实现了系统的功能。
在这次毕业设计中,我还是学了很多东西,许多知识的应用也是第一次。应用UML的建模工具Rational Rose2002,它的很多文档都是英文,学习起来真的很是费工夫,在使用它的过程中我深刻的认识到英语学习的重要性。最重要的还是我的系统,从需求分析、问题域的分析、系统设计到系统实现全部以面向对象的思想为指导,面向对象的思想真的很优秀,它使系统的可维护、可扩展性大大增强。
最后在测试阶段我也是很下了番工夫,感受也颇多。主要如下:首先,应对软件测试感兴趣和对自己有自信,如果具备了这两点,那么在开发过程中不管遇到什么样的困难,我相信你一定能克服。善于怀疑,世界上没有绝对正确的,总有错误的地方,具有叛逆心理,别人认为不可能发生的事,我却认为可能发生。别人认为是对的,我却认为不是对的。 保持一个良好的心情,否则可能无法把测试作好。不要把生活中的不愉快的情绪带到工作中来。做测试时要细心,不是所有的bug都能很容易的找出,一定要细心才能找出这些bug。灵活一些,聪明一点,多制造一些容易产生bug的例子。从客户的角度去测试系统。考虑问题要全面,结合客户的需求、业务的流程、和系统的构架,等多方面考虑问题。当然软件测试虽然辛苦,但是掌握了一定的技巧之后将使你事半功倍。工作中真的需要多总结,多剖析,对于毛病:“有则改之、无则加冕”。软件开发是一件很辛苦的事,只有在工作中多总结,才能找到符合自己的方式方法,才能在工作中事半功倍。
通过毕业设计,我学到了很多很多,有思想方面的,技术方面的,也有做人处世方面的,但让我感受最深刻的受益最深刻的就是:“开发电子商务网站是一项系统工程,不管前期的分析也好,中期的编程也好,后期的实施也好,始终有团结协作贯穿其中,只有将所有的因素都考虑进去,经过不懈的努力,才有可能最后成功!”
致谢
感谢我的导师韩宏老师,这篇论文的每个细节和每个数据表的设计都离不开他的细心指导。而他开朗的个性和宽容的态度,帮助我能够很快的进入我们的毕业设计中。在此论文完成之际,谨向他致以最诚挚的感谢。同时,西北农林科技大学信息工程学院2005年毕业生答辩小组的领导在论文的撰写方面给我们提出了许多宝贵意见,为此论文的顺利进行奠定了基础,在此也向他们表示最诚挚的感谢。
在本次毕业设计过程中,信息工程学院的领导和机房的老师给我们的支持和帮助为设计的顺利进行提供了有利的保障,在此,向他们表示最衷心的感谢。
感谢我的导师老师,对我的毕业设计给予了很大的帮助,并在论文完成上提出了很多宝贵的意见。
感谢我的同学和朋友,我的毕业设计能够顺利完成离不开你们的帮助和参与。
最后,再次向所有指导、支持、帮助和关心过我的各位老师、同学及朋友们表示我最真挚的谢意!
参考文献
[1] 马波 李雄峰 译 Enterprise Java with UML中文版 机械工业出版社 2004年
[2] 冀振燕 编著 UML系统分析设计与应用案例 人民邮电出版社 2004年
[3] 孙卫琴 编著 精通Struts 电子工业出版社 2004年
[4] Alistair Cockburn. 编写有效用例(电子版) 第1版. 机械工业出版社 2002年
[5] http://www.cn-java.com/target/news.php?news_id=2389
[6] http://struts.apache.org/userGuide/dev_tiles.html
[7] http://www.ddvip.net/program/java/index10/32.htm
[8] http://www.ddvip.net/web/asp/index3/67.htm
附录:
需求分析说明书
1. 概述
系统需求是从用户角度对提出问题的认识,它是由一个(或一系列)描述系统要提供的功能的文档组成。它是最终用户、开发者以及系统发起人对系统应该做的和能够做的事情达成的协议。
2. 识别参与者
通过对系统需求的分析,可以确定系统有三个参与者:浏览者、注册用户和管理员。
参与者描述如下:
(1) 浏览者
描述:可以浏览书店的任何图书信息,不能购买图书和对图书发表评论。
示例:拥有上网条件的任何人。
(2) 注册用户
描述:除了浏览书店的任何图书信息,还可以购买图书和对图书发表评论。
示例:填写了正确必要信息的任何人。
(3) 管理员
描述:进行图书的管理和注册用户的管理
示例:书商
3. 识别用例
系统的总体用例参照正文。
4. 系统的事件流描述
用例还可以用事件流来描述,用例的事件流是对完成用例行为所需的事件的描述。事件流描述了系统应该作什么,而不是描述系统应该怎样做,也就是说事件流描述是用域语言描述的,而不是用实现语言描述的。
本系统的用例事件图如下:
1. “用户注册”用例的用例文档
用例名称:用户注册
描述:浏览者通过“用户注册”用例来成为该网络书店的注册用户,任何提供了必须且正确的信息都可以用它。
前置条件:在这个用例执行之前,用户必须登录到本网站。
后置条件:如果用例执行成功,在系统中将会建立用户信息数据。否则系统的状态没有变化。
部署约束:任何一款联网的浏览器产品都可以进入浏览系统。
活动图:见图8-1
2. “用户登录”用例的用例文档
用例名称:用户登录
描述:注册用户通过“用户登录”用例以高级别身份进入系统,任何注册用户输入正确登录信息都可以用它。
前置条件:在这个用例执行之前,用户必须是本系统的注册用户。后置条件:无。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-2
3. “查看书评”用例的用例文档
用例名称:查看书评
描述:浏览者和注册用户通过“查看书评”用例进入系统,用来查看自己所关注的图书书评,以决定自己是否购买该图书。
前置条件:在这个用例执行之前,用户进入本系统。
后置条件:无。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-3
4. “查询图书”用例的用例文档
用例名称:查询图书
描述:浏览者和注册用户通过“查询图书”用例进入系统,任何用户都可以用它来查看自己所关注的图书信息。
前置条件:在这个用例执行之前,用户进入本系统。
后置条件:无。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-4
5. “购物车管理”用例的用例文档
用例名称:购物车管理
描述:浏览者和注册用户通过“购物车管理”用例,查看和管理自己在本系统的购买状态和情况,注册用户可以通过登录系统完全完成购买。
前置条件:在这个用例执行之前,用户必须登入系统。
后置条件:如果执行成功在每个客户端的session里都回保存有购书的信息,注册用户如果购买图书,则数据库也要相应改变;否则无变化。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-5
6. “订单查询”用例的用例文档
用例名称:订单查询
描述:注册用户通过“订单查询”用例,查看自己在本系统的订单情况。
前置条件:在这个用例执行之前,用户必须以注册用户身份登入系统。
后置条件:无。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-6
7. “订单修改”用例的用例文档
用例名称:订单修改
描述:注册用户通过“订单修改”用例,修改自己的下单信息。
前置条件:在这个用例执行之前,用户必须以注册用户身份登入系统。
后置条件:如果执行成功,数据库发生相应改变,否则数据库状态无改变。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-7
8. “创建书评”用例的用例文档
用例名称:创建书评
描述:注册用户通过“创建书评”用例,对书店图书进行客观诚信的评论。
前置条件:在这个用例执行之前,用户必须以注册用户身份登入系统。
后置条件:如果执行成功,数据库发生相应改变,否则数据库状态无改变。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-8
9. “修改书评”用例的用例文档
用例名称:修改书评
描述:注册用户通过“修改书评”用例,对自己的书评进行管理。
前置条件:在这个用例执行之前,用户必须以注册用户身份登入系统。
后置条件:如果执行成功,数据库发生相应改变,否则数据库状态无改变。
部署约束:任何一款联网的浏览器产品都可以进入系统。
活动图:见图8-9
概要设计说明书
1. 概述
概要设计的基线是需求分析,它是从选择技术的角度描述一个系统并将其归类,以便技术人员实现系统。
2. 系统的编码规范
系统从总体上要制定一定的编码书写规范,以提高代码的可读性和可维护性。
2.1 JavaBeans编码规范
1. 命名规范
定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,减少项目组中因为换人而带来的损失。(这些规范并不是一定要绝对遵守,但是一定要让程序有良好的可读性) 。
Package 的命名 Package 的名字应该都是由一个小写单词组成。
Class 的命名 Class 的名字必须由大写字母开头而其他字母都小写的单词组成
Class 变量的命名 变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。
Static Final 变量的命名 Static Final 变量的名字应该都大写,并且指出完整含义。
参数的命名 参数的名字必须和变量的命名规范一致。
2. Java 文件样式
所有的 Java(*.java) 文件都必须遵守如下的样式规则版权信息 。
版权信息必须在类声明之前,比如:
/**
* Title: 关注图书业务类
* Description: 毕业设计作品
* Copyright: Copyright (c) 2005
* Company: nwsuaf
* @author: stone & meteoroids
* @version 1.0
*/
其他不需要出现在 javadoc 的信息也可以包含在这里。
Package/Imports package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含了同一个包中的不同子目录,则应该用 * 来处理。
2.2 JSP编码规范
从系统的可维护性和可扩展性两方面出发,已经将JSP页面内内嵌的JAVA代码减少到很少,剩余有JAVA代码的JSP页面中,必须使JAVA代码和静态的HTML代码严格书写,回车分开。具体如下:
静态文件脚本部分采用Javascript编写。输出部分采用HTML标记语言。
* 一个标记必须占用一行。不得出现两个标记在同一行的情况(同一标记的关闭标记除外)。
* 静态文件内容必须包含在<body></body>标记中间
* <body>标记必须包含在<html></html>标记中间
动态部分,一个独立的页面,首行必须是<%@ page contentType="text/html;charset=GBK"%>,下来是<%@ page import=”***”%>,然后是<jsp:useBean id=”***” name=”***”/>,最后是页面体。
3. 问题域的分析类
3.1 各分析类概述
实体类之间的关系如下图9-1所示(为方便起见,并没有包含各实体类的方法)
系统业务逻辑类的概述如下图9-3:
3.2分析类分组概述
1. 实体对象类,这组类大部分反映现实世界中的一个实体。
2. 业务对象类,这组类主要是对实体类的操作,它们的行为构造出系统的大部分功能。
3. 值对象类,这组类是对象类未存入数据库前所表现的存在方式。
4. 流程控制类,这组类是对客户请求进行分析,根据XML文件配置控制处理请求程序的转向类。
5. 实用工具类,这组类既有数据库连接操作类,也有不同标准文本的格式转换类和国际化问题的解决类。
6. 用户界面类,这组类完全封装了数据显示和系统同用户交互的逻辑,这了里我们采用JSP技术。(本系统包括客户界面和管理员界面)
3.3系统总体构架图
见正文4.1.4
4. 系统的技术要求
4.1 用户界面
1. 用户界面复杂度
本系统的界面按照以下复杂度进行考虑:简单数据输入、数据的静态视图、可定制视图、数据的动态视图、交互式视图。本分组有后台JSP页面和前台JSP页面。
用户JSP页面放在web根目录下,管理员JSP页面放在manage目录下。
2. 用户界面的部署约束
后台JSP页面和前台JSP页面可以在任何一台连网的装有任何一款浏览器的计算机上访问。效果应如下(示例):
在netscape8.0浏览器中,界面如下图9-4所示:
在firefox1.0.4浏览器中,界面如下图9-5所示:
在IE6.0浏览器中,界面如下图9-6所示:
4.2 可用带宽
从用户的需求中看,不管是拨号接入internet还是ADSL方式接入internet,都应该可以快速浏览网页,采用页面各部分分离技术实现可用带宽的拓展。
5. 系统的接口设计
5.1 用户接口
db.properties文件提供系统与数据库进行性的属性值;
bookdatabase.sql提供创建系统所需数据库结构的SQL语句;
5.2 外部接口
Internet协议:TCP/IP协议;
局部网络的协议:PPPOE协议。
SQL Server 2000驱动程序:msbase.jar 、mssqlserver.jar和msutil.jar
5.3 内部接口
org.nwsuaf.util.DBConnectionManager 系统与数据库进行连接接口;
org.nwsuaf.web.book.shop 提供用户信息与定单之间的接口;
org.nwsuaf.web.book.bookclass 提供图书类别和图书具体信息之间的接口;
6 系统出错处理设计
6.1 出错信息
| 出错原因 | 系统输出信息 | 含意及处理方法 |
1 | 用户未注册 | 对不起,请您注册 | 转向用户注册页面 |
2 | 用户输入购书数量超过库存 | 对不起,请更改购书数量 | 转向购书页面 |
3 | 非管理员登陆 | 对不起,您没足够权限 | 转向首页 |
4 | 图书信息不规范 | 对不起,您不能插入信息 | 转向提交表单 |
5 | 其他(数据类型不匹配等) | 系统内部错误 | 重新输入 |
6.2 补救措施
1. 后备技术:
1) 为防止原始系统数据万一丢失采用周期性把磁盘信息记录到磁带上去;
2) 为防止管理员丢失数据或不法行为,利用log4j日志备分技术备分各项操作的详细情况;
2. 恢复及再启动技术:将数据库备分还原。
特色代码
中文乱码解决问题
SetCharacterFilter.java
public class SetCharacterEncodingFilter implements Filter
{
/** 编码 */
protected String encoding = null;
protected FilterConfig filterConfig = null;
/** 是否忽略要转换成的编码 */
protected boolean ignore = true;
public void init(FilterConfig filterConfig) throws ServletException
{
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
{
this.ignore = true;
}
else if (value.equalsIgnoreCase("true"))
{
this.ignore = true;
}
else if (value.equalsIgnoreCase("yes"))
{
this.ignore = true;
}
else
{
this.ignore = false;
}
}
/**
* 实现具体的过滤转换编码功能。
*
* @param request 对应JSP中的request对象。
* @param response 对应JSP中的response对象。
* @param chain 过滤器链对象。
* @throws IOException 向上抛出IOException异常。
* @throws ServletException 向上抛出ServletException异常。
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
// 按条件选择并设置要使用的编码。
if (ignore || (request.getCharacterEncoding() == null))
{
String encoding = selectEncoding(request);
if (encoding != null)
{
request.setCharacterEncoding(encoding);
}
}
// 传递控制到下一个过滤器。
chain.doFilter(request, response);
}
web.xml
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>org.nwsuaf.util.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<init-param>
<param-name>ignore</param-name>
<param-value>false</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
…….
由于篇幅关系,其他特色代码见程序。