JSP+SQL网上书店销售系统(论文+系统)
收藏
资源目录
压缩包内文档预览:
编号:149932649
类型:共享资源
大小:7.18MB
格式:RAR
上传时间:2021-10-10
上传人:好资料QQ****51605
认证信息
个人认证
孙**(实名认证)
江苏
IP属地:江苏
20
积分
- 关 键 词:
-
JSP
SQL
网上
书店
销售
系统
论文
- 资源描述:
-
JSP+SQL网上书店销售系统(论文+系统),JSP,SQL,网上,书店,销售,系统,论文
- 内容简介:
-
引引 言言二十一世纪是一个集数字化,网络化,信息化的,以网络为核心的社会。当钱天白教授于 1986 年 9 月 14 日在北京计算机应用技术研究所内向德国卡尔斯鲁厄大学发出第一封电子邮件“穿越长城,走向世界”的时候,他也许不知道自己推开了中国信息时代的大门;1994年 4 月 20 日,中国科学院计算机中心通过美国 Sprint 公司连入 Internet 的 64K 国际专线开通,实现了国际互联网的全功能连接,从此中国迈入互联网信息时代。转眼间互联网在中国已有 10 余年的发展,中国的网民充分领略到“畅游天地间,网络无极限” 所带来的畅快。随着 Internet 的飞速发展,使得网络的应用日益的广泛。如电子商务,电子政务,网上医疗,网上娱乐,网络游戏,网络教学等。本次毕业设计的题目就是网上书店系统。本论文就毕业设计的内容,系统地阐述了整个网上书店系统的功能及实现。我们小组人员在指导老师的带领下设计并实现了从商品管理,商品分类和查询,到购物车实现,用户订单处理,再到聊天室,管理员系统。基本上实现了电子商务的功能流程,能够实现用户与商家在网上进行商品交易。本系统界面简单直观,易于操作和使用,交互性强,完全基于Internet 网络。 本系统在 XX 老师指导下,由我们小组共同开发完成。限于时间有限,在系统安全性等方面仍需进一步深入研究。另外,疏漏和不妥之处,在所难免。真诚的希望老师予以指导和纠正。Abstract:The 21st century is a collection digitization, the network, the informationization, take network as core society. When Qian Tian taught without charge gives sends out the first email in September 14, 1986 in Beijing computer applied technology research institute introversion Germany Karlsruhe University “to pass through the Great Wall, moved toward the world” time, perhaps he did not know that he has opened China information age front door; on April 20, 1994, the Chinese Academy of Science computer center entered Internet through the American Sprint Corporation company the 64K international special line clear, has realized internets entire function binding, henceforth China entered into the Internet information age. The Internet had 10 remaining years of life development in a moment in China, Chinas web cams understands fully “enjoys a trip to between the world, the network does not have carefree which the limit” brings. Along with the Internet swift development, causes the network application day-by-day widespread. If electronic commerce, E-government, on-line medical service, on-line entertainment, network game, network teaching and so on.This graduation projects topic is on-line books management system managemen 第一章第一章 开发背景开发背景1.11.1 目的和意义目的和意义本系统的设计目的是为了满足消费者只要通过互联网就可以足不出户的购买自己喜欢的图书,改变传统商业交易,在互联网上进行交易,实现网上购买图书。为了实现上述目的,我对网上书店系统有了深一步的了解,从而满足客户的要求,让他们可以随时找到自己想要购买的图书。本论文课题新颖,主要涉及软件,数据库与网络技术等。涵盖知识面广,可有效地提高学生综合运用所学知识分析解决问题的能力,增强学生对事物的理解与掌握能力,培养学生掌握科学的研究方法,正确的设计思想,独立思考,勇于进取,探索创新,为今后进一步学习与工作奠定了良好的基础。1.21.2 开发设计思想开发设计思想本系统用 JSP 语言来编写网络书店系统,数据库用 Microsoft SQLServer2000 来连接系统,通过编写 JavaBeans 来进行后台业务逻辑控制,即 JSP +JavaBeans + SQLServer2000三层模式完成整个设计工作。本系统全部基于 Internet 网络,以 JSP 语言对网站进行开发,注重用户与网站的交互性。因此在这样的背景下,针对当前 Internet 网络发展趋势来计网络书店系统就成为了当今应用软件的首选体系结构。1.31.3 开发目标开发目标 网上购书的优势在于选择面大、价格便宜、交易方便、节省时间和精力等。整个图书市场一片繁荣,在这种情况下,网上书店的加入无疑将使得竞争更加激烈,但从另一个方面看,只有在这种激烈的竞争下,网上书店的优势才能得以体现。在中国,网上书店有发展的必要,也有发展的基础,发展网上书店的各方面条件也日趋成熟,但是还存在一些问题,只有把问题解决好了,才能保证网上书店的蓬勃发展,第二章第二章 开发工具和环境简介开发工具和环境简介2.12.1 JavaJava ServerServer PagePage 简介简介Java Server Page或简称为JSP是由Sun公司在Java语言上开发出来的一种动态网页制作技术,它提供了一种建立动态网页的简单方法,并为开发人员提供了一个Server端框架,基于这个框架,开发人员可以综合使用 HTML,XML,JAVA语言以及其他脚本语言,灵活,快速地创建和维护动态网页,特别是目前的商业系统。作为JavaTM 技术的一部分,JSP能够快速的开发出基于所有Web服务器和应用服务器环境,独立于平台的应用程序,而且具有非常强的可伸缩性。同时,JSP把用户界面从系统内容中分离开来,使得设计人员能够在不改变底层动态内容的前提下改变祖国网页布局。这样跨平台的特性己包含了目前大部份网站服务器配置环境,再加上它的语法写作方式可媲美ASP般的易学易懂,而且在网络安全技术方面甚至已超越ASP技术。所以,相信很快的时间内极有可能取代现有网页编译技术,而成为商业网站的新标准。在本节中我们将会讨论JSP技术的特性,让您更加了解这项新技术。2.22.2 MicrosoftMicrosoft SQLServer2000SQLServer2000 简介简介SQLServer2000是一个基于关系型数据库模型建立的数据库管理系统软件(DBMS)。它帮助用户方使地得到所需信息,并提供强大的数据处理工具。它可以帮助用户组织和共享数据库信息,以便于根据数据库信息作出有效的决策。另外,仅有这样个数据库管理系统软件(DBMS),则只能进行一些信息系统所需要的简单数据处理,且对操作者有较高的操作技能要求。因此,信息系统的开发者都是在某种数据库管理系统软件DBMS环境下编写相应的应川程序,以形成一个能够满足应用需求且操作尽可能简单的应用型信息系统,这被称之为二次开发。 SQLServer2000 还具有以下特点:1使信息更易于查找和使用SQLServer2000继续为简便地查找信息提供易于使用的工具。2支持 Web 功能的信息共享SQLServer2000 可以通过企业内部网络Internet 很简便地实现信息共享,而且它可以很容易地将数据库定位到浏览器中,它将桌面数据库的功能和网站的功能结合在一起。3用于信息管理的强大解决方案高级用户和开发人员可以创建那些将SQLServer2000界面(客户端)的易用性和SQL服务器的可扩展性和可靠性结合在一起的解决方案。4改变了数据库窗口可在SQLServer2000容纳并显示新的对象,增强了SQLServer2000 数据库的易用性。5提供名称自动更正功能自动解决当用户重新命名数据库对象时出现的常见负面效应。例如,当用户重命名表中的字段时,将自动在诸如查询的相关对象中进行相应的更改。6具有子数据表功能子数据表在同一窗口中,提供了嵌套式的视图,这样就可以在同一窗口中专注于相关的数据并对其进行编辑。7 用户只需简单地将SQLServer2000对象(表、查询等)从数据库放到ODBC数据源中,即可从 Microsoft SQLServer2000中将数据导出到Microsoft ACCESS 2000 。8数据访问页功能该功能可使用户快捷方便地创建数掂 HTML页,并通过数据 HTML页,将数据库应用扩展到企业内部网络 Internet上。这将帮助用户比以往更快捷、高效的方式共享信息。9共享组件的集成SQLServer2000利用新的 Web组件和位于浏览器中的 COM 控件,为用户提供了多种查看和分析数据的方式。10Microsoft SQL Server 交互性Microsoft SQLServer2000支持OLE DB,使用户可以将SQLServer2000 界面的易用性与诸如 Microsoft SQL Server的后端企业数据库的可升级性相结合。2.32.3 JDBCJDBC 驱动程序简介驱动程序简介从编程的角度出发,有两个主要的类负责建立与数据库的连接。第一个类DriverManager 是在 JDBC API 中提供的为数不多的实际类。 DriverManager 负责管理已注册驱动程序的集合,实质上就是提取使用驱动程序的细节,这样程序员就不必直接处理它们。第二个类是实际的 JDBC Driver 类。JDBC 驱动程序有四种类型。 第一种驱动程序:它们都使用 JDBC-ODBC 桥,这是作为 JDK 的一个标准部分包括的。第一种驱动程序通过附加在 JDBC-ODBC 桥的“开放式数据库连接性”(Open DataBase Connectivity(ODBC)驱动程序来区分。要连接到一个不同的数据源,您只需要使用 ODBC 管理员注册(或有效地绑定)一个不同的 ODBC 数据源到合适的数据源名称即可。 第二种驱动程序也称为部分 Java 驱动程序,因为它们直接将 JDBC API 翻译成具体数据库的 API。对于分布式应用程序,这种需求会产生额外的许可证问题,还可能带来可怕的潜在代码分布问题。第三种驱动程序是纯 Java 驱动程序,它将 JDBC API 转换成独立于数据库的协议。JDBC 驱动程序并没有直接和数据库进行通讯;它和一个中间件服务器通讯,然后这个中间件服务器和数据库进行通讯。这种额外的中间层次提供了灵活性:可以用相同的代码访问不同的数据库,因为中间件服务器隐藏了 Java 应用程序的细节。要转到不同的数据库,您只需在中间件服务器上改变参数。 第四种驱动程序是纯 Java 驱动程序,它直接与数据库进行通讯。很多程序员认为这是最好的驱动程序,因为它通常提供了最佳的性能,并允许开发者利用特定数据库的功能。当然,这种紧密耦合会影响灵活性,特别是如果您需要改变应用程序中的底层数据库时。这种驱动程序通常用于 applet 和其它高度分布的应用程序。2.42.4 JavaBeansJavaBeans 简介简介JavaBeans是一个可以重复使用的软件组件。实际上JavaBeans是一种Java类,通过封装属性和方法成为具有某种功能或者处理某个业务的对象,简称beans。JavaBeans是基于Java语言的,具有以下特点:(1)可以实现代码的重复利用。(2)易编写,易维护,易使用。(3)可以在任何安装了Java运行环境的平台上的使用,而不需要重新编译。2.52.5 JAVAJAVA 简介简介 Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象。Java的源代码在传递到客户端执行之前,必须经过编译,因而客户端上必须具有相应平台上的仿真器或解释器,它可以通过编译器或解释器实现独立于某个特定的平台编译代码的束缚。Java采用强类型变量检查,即所有变量在编译之前必须声明。Java是一种与HTML无关的格式,必须通过像HTML中引用外媒体那么进行装载,其代码以字节代码的形式保存在独立的文档中。Java采用静态联,即Java的对象引用必须在编译时的进行,以使编译器能够实现强类型检查。Java语言是一种与平台无关的编程语言,它具有“一次编写,随处运行”的特点,所以,非常适合于分布式的网络编程。随着 Internet网络在我国的迅速普及,参与和从事网络编程的人员也在不断地增加,同时,也将有更多的网络开发者选用Java语言作为编程工具,而一些C和C+程序员也在逐步转向应用Java语言编写程序。2 26 6 电子商务简介电子商务简介电子商务源于英文 ELECTRONIC COMMERCE,简写为 EC。顾名思义,其内容包含两个方面,一是电子方式,二是商贸活动。 电子商务指的是利用简单、快捷、低成本的电子通讯方式,买卖双方不谋面地进行各种商贸活动。 电子商务可以通过多种电子通讯方式来完成。简单的,比如你通过打电话或发传真的方式来与客户进行商贸活动,似乎也可以称作为电子商务;但是,现在人们所探讨的电子商务主要是以 EDI(电子数据交换)和 INTERNET 来完成的。尤其是随着 INTERNET 技术的日益成熟,电子商务真正的发展将是建立在 INTERNET 技术上的。所以也有人把电子商务简称为 IC(INTERNET COMMERCE) 。 要实现完整的电子商务还会涉及到很多方面,除了买家、卖家外,还要有银行或金融机构、政府机构、认证机构、配送中心等机构的加入才行。由于参与电子商务中的各方在物理上是互不谋面的,因此整个电子商务过程并不是物理世界商务活动的翻版,网上银行、在线电子支付等条件和数据加密、电子签名等技术在电子商务中发挥着重要的不可或缺的作用。总的来说,正如大家所熟知的那样,电子商务可以分为企业(Business)对终端客户(Customer)的电子商务(即 B2C)和企业对企业的电子商务(B2B)两种主要模式。提起 B2C,大家可能更为熟悉一些,它是从企业到终端客户(包括个人消费者和组织消费者)的业务模式。今天所谈的电子商务时代的 B2C 是通过电子化、信息化的手段,尤其是互联网技术把本企业或其它企业提供的产品和服务不经任何渠道,直接传递给消费者的新型商务模式。因为它与大众的日常生活密切相关,所以被人们首先认识和接受。电子商务 B2C 模式的一种最为大家所熟悉的实现形式就是新兴的专门做电子商务的网站。现在,仿佛一夜之间,涌现出无数的这类公司,其中有网上商店、网上书屋、网上售票等等,甚至还有一些什么都做,什么都卖的电子商务网站,人们戏称为“千货公司”的。但无论怎样,这些新型模式企业的出现,使人们足不出户,通过因特网,就可以购买商品或享受咨讯服务。这无疑是时代的一大进步。在这些新涌现出来的互联网公司中,亚马逊公司可以说是最具代表性的一例。人们在反思亚马逊的亏损原因时意识到,也许不应该将建立起电子商务时代 B2C 的任务全都寄托于这些白手起家的网站上,传统行业自觉的互联网和电子商务革命也许会更经济,更实惠,也更必要,不至于给投资人、给股民带去那么多的压力和担忧。也许,只有当这两股力量都齐齐奔向同一个山顶时,这样的电子商务世界才更精彩,真正的电子商务时代也才会更快一些到来。传统企业成功向互联网和电子商务转型最成功的例子是 DELL,DELL 一开始还只是一家通过电话直销电脑的公司,尽管也很成功,但当互联网革命开始之时,它毫不犹豫地选择了把握机遇,将自己的全部业务搬到了网上去,并按照互联网的要求来对自己原有的组织和流程进行梳理,开发了包括销售、生产、采购、服务全过程的电子商务系统,并充分利用了互联网手段,为用户提供个性化定制和配送服务,大大提高了客户的满意度,奇迹般地保持了多年 50%以上的增长,成为今天世界最大的电脑厂商之一,也对其它转型较慢的竞争对手造成了巨大的威协和挑战。B2C 的这二种实现方式还有一点很大的不同,由网站起家的 B2C 较难发展起自有品牌的产品、实业,因此它们更象是一个百货商店,当然与百货商店最不同的就是百货店是用户上门的,而 B2C 网站是送货上门的,而由传统企业改造而来的 B2C 更可能象是一个专卖店,专营自己品牌的产品,与传统专卖店不同的是:这里用户和厂商互动性更强,可以量身定做,同时由于省去了建物理店的开销,成本可能会降低。谈完了 B2C 再来说说 B2B,企业与企业之间的业务模式被称作 B2B,电子商务 B2B 的内涵是企业通过内部信息系统平台和外部网站将面向上游的供应商的采购业务和下游代理商的销售业务都有机地联系在一起,从而降低彼此之间的交易成本,提高满意度。实际上面向企业间交易的 B2B,无论在交易额和交易领域的覆盖上,其规模比起 B2C 来都更为可观,其对于电子商务发展的意义也更加深远。与 B2C 相似,B2B 在企业间的应用也有两种主要实现形式。B2B 的一种实现是其在传统企业中的应用。一些传统企业的实质性业务,正在逐步向B2B 转变,更多地以 WEB 方式来传递信息和实现网上订单,但物流方式就和以前没什么变化,依然是供应商到本企业,本企业再到代理商或最终客户。以通用汽车为例,通用汽车建立了一个 B2B 电子商务网站TradeXchange,计划在今年年底之间,将其每年高达 870 亿美元的采购业务完全通过该网站进行。并且这个网站不仅满足通用自身的采购业务,其30000 多家供应商也将在这一系统上进行交易,它将对通过 TradeXchange 进行的电子商务交易收取 1%的的手续费,专家们估计这将为通用汽车带来每年 50 亿美元的收入。 但正如我在前面第一部份举例时所提醒的那样,不要把互联网和电子商务仅仅看作是一个工具,它同样可能对营销模式和管理模式带来变革,B2B 的第二种实现方式就有这样的意味。这一类的 B2B 公司并不是为自身企业的采购或销售服务的,它自身可能不生产任何产品,但它通过建立统一的基于 WEB 的信息平台,为某一类或某几类的企业采购或销售牵线搭桥,此时物流的方式就和上一类有很大不同了,它是由供应商直接到代理商。比如说我们前面第一部份中例举的那间 B 公司就有一点类似这种公司。它搭建了计算机零部件这一类商品卖家和买家的桥梁,因此它没有厂房,甚至没有库房,而只是通过信息系统来调配、组织供货与销售,并提供一些增值性服务,从而获得佣金或增值性服务收入。当然这一类公司成功的关键是它要能聚拢这一类产品的卖家和买家,通过特色服务,让它们愿意到你的平台上来交易,但究竟愿不愿意,这也和 B2C 中所谈到的是选择百货店还是专卖店方式有些类似。第三章第三章 书店系统功能分析书店系统功能分析为了最终实现目标系统,必须设计出组成这个系统的所有程序和文件(或数据库) 。模块是数据说明、可执行语句等程序设计对象的集合,它是单独命名的而且可通过名字来访问。模块化就是把程序化分成若干个模块,每个模块完成一个子功能,把这些模块集起来组成一个整体,可以完成指定的满足问题的要求。3 31 1 系统功能分析系统功能分析首先对现有系统进行分析,现有系统是信息的重要来源。分析已有系统的功能和实现,从而确定新系统的设计目标和模型。由于条件有限,调研主要是在网上进行。即通过在网上已有的图书网站注册成会员来了解其具备的功能。1从用户角度来看:用户通过在线注册成为网站的用户,可以获得以下功能:书目浏览,购买图书,查看订单,修改订单,修改密码,修改个人信息,书籍简介,投票箱等。另外,用户注册成功后,可以进入到网站的留言板块进行留言等。2.从网站的角度看:(1)网站应该包含商品搜索功能:按书名(模糊)查询。(2)订单处理功能,确认订单方式:a). 电话通知方式b). E-mail 方式(3)管理员管理:查看用户信息,并根据用户信息和用户订单对商品进行发派。(4)书目浏览a).书名b).出版社c).作者d).价格e).订购号(5)好书的投票查看用户好书投票的信息及投票百分比的评比。(6)论坛用户进行信息交流的地方,可以在留言板进行留言,为查找图书提供好的网站等等。3 32 2 可行性研究可行性研究可行性研究阶段的主要任务是在系统初步调查的基础上,对新系统是否能够实现和值得实现等问题做出判断,避免在花费了大量的人力和物力之后才发现系统不能实现或新系统投入使用后没有任何实际意义而引起的浪费,对新系统可行性的分析,要求用最小的代价在尽量短的时间内确定系统是否可行。技术可行性分析网上书店系统的开发是一项复杂的系统工程。为了保证系统开发成功,必须采用工程化的系统开发方法,并研究出一些符合工程化标准的开发方法。这些方法旨在指导开发者进行工程化的系统开发,从而加快系统开发的速度,保证质量以及降低开发成本。工程化的系统开发方法确实在开发实践中取得了一定的效果。此次开发使用JSP作为开发语言,采用Servlet技术,Tomcat5.0作为Web服务器。运行可行性分析: 随着计算机知识的普及和推广,越来越多的人掌握了计算机的基本使用方法和技能。随着 Internet 的发展,用户对于网络、WINDOWS 等环境下的软件使用比较熟悉,对于新鲜事物,用户表现出极大的兴趣和热情。 经济可行性分析: 网上图书系统给人们带来了方便,成为一种全新的商务模式。因此,不用出门就可以在家购物的新时尚已经到来,构建一个网上书店系统在经济上是完全可行的。就本系统而言,随着各地大学城的兴建,校园远离市区,学生出校买书的代价提高。另一方面,随着宽带网络进入校园,为学生在网络上进行购物提供有利的条件。而一个网上书店系统可以为学生提供软件条件,这样学生便可以足不出户的买书了。商家可以从中获得利润,两全其美。通过以上的分析,开发网上书店系统是完全可行的。运行环境: 本系统采用联网多机多用户操作方式,系统的运行环境包括硬件、操作系统、关系数据库等软件:硬件:中央处理器(CPU):PI 以上的处理器;硬 盘:10GB 以上硬盘;软 驱:1.44MB 软驱;内 存:128MB;显示器:15 寸/17 寸显示器;操作系统:Windows 2000,Windows NT,Windows XP, Unix, Linux;关系数据库:Microsoft SQLServer2000;3 33 3 需求分析需求分析需求分析的任务是通过详细调查现实世界要处理的对象,充分了解系统的工作概况,明确用户的各种需求,然后在此基础上确定新系统的功能。新系统必须充分考虑今后可能的扩充和改变。1在这里我们需要了解用户有什么样的具体要求和对系统性能的要求。(1)用户的需求分析:(a)用户注册(b)用户登录(c)书目浏览(d)图书订购(e)书目查询(f)订单修改(g)修改密码(h)修改个人信息(i)留言板(j)管理员(2)系统性能分析对数据的安全性、完整性要求:用户信息保密,只有管理员可见(可查) ,但不能任意修改。确保网上支付安全。商品信息、用户信息必须保证其完整性。防止恶意删改。以下是系统性能需求:(a)准确性和可靠性高(b)页面友好,功能齐全,且可以使用(c)系统便于维护和升级。(d)数据库访问效率高3 34 4 系统总体结构图:系统总体结构图:数据流图:数据流图:是一种描述软件系统逻辑模型的图形符号。这种图形表示即可以从本质上描述计算机软件系统的工作情况,又适合非计算机专业人员学习和掌握,在需求分析中是一种很好的交流和表达工具。带箭头的线表示数据流,其中箭头表示了数据的流动方向。网上书店系统用户注册用户登录修改个人密码订单查询修改个人信息修改订单留言板图书浏览图书查询 管理员圆框表示对数据的加工。方框表示数据的起点和终点。画分层数据流图。分层数据流图: (a)书店系统 E-R (b)检查书店系统E-R图检查合法性用户信息处理查询处理不合法处理留言处理投票处理订单处理系 统网上书店系统用户注册信息用户登陆信息图书浏览信息留言板信息用户信息修改信息用户订单修改信息用户基本信息文件用户信息处理录入处理 (c)用户基本信息处理E-R图 (d)用户留言处理 E-R 图修改信息修改密码留言处理添加留言处理私人留言删除处理留言信息文件公共留言私人留言订单处理添加处理订单信息文件(e)用户订单处理E-R图(f)书籍查询处理 E-R 图(g)投票箱 E-R 图修改处理删除处理投票处理投票结果百分比处理投票信息文件查询处理书籍总览具体书名查询管理员登陆删除定购图书信息添加图书管理员信息文件(h)管理员 ER 图3 35 5 数据字典:数据字典: 字典的作用是给词汇以定义和解释。在结构化分析中,数据字典的作用是给数据流图上每个成分以定义和说明。换句话说,数据流图上所有成分的定义和解释的文字集合就是数据字典。数据字典对数据流图和各种成分起注解说明作用,给这些成分赋以实际的内容。除此之外,数据字典还要对系统分析中其他需要说明的问题进行定义和说明。数据字典描述的主要内容有:数据流、数据元素、数据存储、加工、外部项。其中数据元素是组成数据流的基本成分,在系统分析中,数据字典起着重要的作用。3 36 6 需求分析复审需求分析复审 需求分析说明书完成后,应由用户和开发人员共同复审,复审小组对需求分析说明书的各个部分逐个进行认真的复查,确认文档所描述的系统模型符合用户的需求,复审结束后双方签字确认。删除图书删除用户 本次需求分析有老师布置并指导。小组成员亲自调查,并经小组分析讨论后制定系统需求功能目标。第四章第四章 网上书店总体设计网上书店总体设计4 41.1.系统功能设计目标系统功能设计目标理论系统功能设计目标如下:(1) 实用性强:我们努力使系统符合实际操作流程的习惯,并尽量减少用户的输入,易学易用的友好的用户界面,满足各层次的用户使用的需求;(2) 先进的程序结构:使用当代前卫的软件编程,能延长其生命周期,易于维护与管理;(3) 安全可靠性高:后台维护功能齐全,根据平台在各个阶段不同的使用情况,管理人员可以设置相应的操作权限,增加系统注册,分配各个栏目的管理权限,实现系统的维护,保证系统的安全、可靠;(4) 使用模块化设计的方法:使系统具有良好的可扩充性,以适应其不同阶段的发展需要,便于后来者分析、维护;(5) 操作简单,维护方便:每个子系统都具有相对独立的系统维护功能对可变化的项目可自行维护;(6) 查询功能强大:可以对商品的基本情况、用户基本情况,书评信息,用户留言等按各种方式查询,可形成各种表单,同时还可对其进行汇总,使管理人员能及时准确地掌握用户和商品等的基本情况。4 42 2. .网网上上 书书店店 系系统统功功能能模模块块划划分分:根据需求分析与系统功能设计目标,结合实际情况本系统功能模块设计分为如下几个模块:1主页:在这里我们可以看见本系统的主要功能和信息。2用户注册:在这里我们可以注册我们的基本信息,其中电话和 Email 是比较重要的,因为我们需要对这些信息进行处理,以方便用户的付款和邮购。3用户登陆:为了方便用户的付款,邮购和管理,我们需要变成会员后才可以进行消费。4书目浏览:成功登陆后的用户可以分页浏览图书书目,并将想要的图书提交到填写订单页面。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登录页面” 。5订购图书:成功登陆的用户可以在该页面定购所需要的图书。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。6查看订单:成功登陆的用户可以在该页修改已经订购的图书。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。7修改订单:成功登陆的用户可以在该页修改或删除已经订购的图书。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。8书目查询:成功登陆的用户可以在该页查找自己需要的图书。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。9修改密码:成功登陆的用户可以在该页修改自己的密码。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。10修改个人信息:成功登陆的用户可以在该页修改自己当初注册时的信息。如果用户还没有注册就直接进入或者没有成功登陆就进入页面,将被连接到“用户登陆页面” 。11留言板:成功登录的用户可以在该页留言。12管理员:查看用户订单,查看用户信息,并根据用户信息和用户订单对商品进行发派。4 43 3 网上书店的体系结构网上书店的体系结构:三层结构:视 图逻辑处理数 据 库即: JSP 技术 + JavaBeans + SQLServer2000 数据库第第五五章章 数数据据库库设设计计5 51 1 数据库系统概述数据库系统概述:数据库系统是在文件系统的基础上发展而来的,经历了层次数据库、网状数据库、关系数据库三个阶段。由于关系数据库采用人们比较容易理解和接受的二维表格来组织数据,发展迅速,已成为数据库产品的主流。本系统的前端开发是使用 JSP 技术,通过 JavaBeans 进行逻辑控制和数据库连接,而后台数据库采用的是 SQLServer2000。SQLServer2000 数据库管理系统是一项全面完整的数据库与分析产品。SQLServer2000 非常容易学习、使用,介绍、学习资料比较多,SQLServer2000 全面支持 Web 功能的数据库解决方案,与此同时,SQLServer2000 还在可伸缩性与可靠性方面保持着多项基准测试纪录,而这两方面特性又都是企业数据库系统在激烈市场竞争中克敌致胜的关键所在。无论以应用程序开发速度还是以事务处理运行速度来衡量,SQLServer2000 都堪称最为快捷的数据库系统。对比 SQLServer2000 和其他的大型数据库管理系统,SQLServer2000 具有可靠的安全性,较快的存储速度,高度的兼容性,简单易用,应用SQLServer2000 作为后台数据库为系统的开发提供了强有力的支持,并对以后软件的运行提供了坚实的基础,因此,我们采用了 SQLServer2000 作为后台数据库。5 52 2 数据库表设计:数据库表设计:本系统的数据库其中包括九个表,分别为图书书目表 book, 用户注册表 member, 管理员表 admin, 书籍类型表 booktype, 评论表 commont, 购物车表 gouwuche, 新闻表news,定单表 num,定单详细信息表 orderbook。详情请见下面的数据库表: 1、图书书目表 booK2、管理员表 admin3、新闻表 news4、书籍类型表 booktype5、用户注册表 member6、定单详细信息表 orderbook7、定单表 num第六章第六章 程序设计程序设计6 61 1 程序说明程序说明根据前边的需求分析和系统总体设计内容进行程序设计。本系统是以 Java 语言为基础进行开发的。我个人负责的模块主要是采用 JSP 技术+JavaBeans+ SQLServer2000 模式进行模块开发与实现的。全部都以面向对象的方法进行设计和实现。一在程序设计时,我用到了下面的一些定义,解释如下:1Page 用来定义整个 JSP 页面的一些属性和这些属性的的值。2Page import 该属性的作用是为 JSP 页面引入 JAVA 核心包中的类,这样就可以在 JSP 页面的程序片部分,变量及函数声明部分,表达式部分使用的类。可以为该属性指定多个值,该属性的值可以是 JAVA 某个包中的所有类或一个具体的类。3include file 表示的是静态的插入一个文件。6 62 2 具体模块划分具体模块划分1 .主页面模块 主页面中上部包含:标题:欢迎光临网上书店此刻访问的时间和访问本站的人数等部分。2用户注册模块 用户注册是为第一次登录网站的用户所设计的。在用户成为本站用户之前一定要注册才可以访问我网站的其它网页。用户注册包括:登录名称,真实姓名,设置密码,电子邮件等。注册成功后,才可以访问本站的其他页面。此模块是我负责的。 3用户登录模块 用户登录包括:登录名称,输入密码。当用户登录后由管理员核对该用户的名称和密码是否正确,如果无误的话用户可以通过检查直接进入网站的其它页面进行浏览和订购。4书目浏览模块 (此模块是我负责的)书目浏览:成功登陆后的用户可以分页浏览图书书目,并将想要的图书提交到填写订单页面。5订购图书模块订购图书:成功登陆的用户可以在该页面定购所需要的图书。6查看订单模块查看订单:成功登陆的用户可以在该页修改已经订购的图书。7修改密码模块 (此模块是我负责的)修改密码:成功登陆的用户可以在该页修改自己的密码。第七章第七章 软件安装与调试软件安装与调试7 71 1 软件的安装与配置软件的安装与配置(1)软件安装:操作系统 Windows XP Microsoft SQLServer2000 JDK 安装:JDK 安装特别简单,和安装其他的软件没什么区别。 JDK 的配置:设置 JAVA_HOME 环境变量:JDK 安装目录 例:C:j2sdk1.4;设置 CLASSPATH 环境变量:JDK 安装目录libtools.jar 例:C:j2sdk1.4libtools.jar;.设置 PATH 环境变量:JDK 安装目录bin;例:C:j2sdk1.4bin;服务器的安装:Tomcat 5.0设置 TOMCAT_HOME 环境变量:Tomcat 安装目录 例:C:Tomcat 5.0;(2)安装 Tomcat5.0 安装时注意在选择 Java 虚拟机路径是一定要选择安装的 JSDK 的目录,然后再开始安装。(3)安装完毕后,启动 TOMCAT,然后再浏览器中输入 http:/localhost:8080 时可以看见TOMCAT 的欢迎页面,这时表示配置成功了。7 72 2 软件软件调试调试 系统调试的目的是发现程序和系统中的错误并及时予以纠正。在网上书店系统中用的调试方法也包括这些:(1) 程序调试包括语法调试和逻辑检查,测试数据除采用正常数据外,还应用一些异常资料,用来考验程序的正确性。用正常资料调试。用异常资料调试。用错误资料调试。7 73 3 软件软件测测试试:软件的测试是系统开发周期中一个十分重要的环节,其重要性体现在它是保证系统质量与可靠性的最后关口,是对整个系统开发过程的最终审查,如果错误不能在测试阶段被发现并纠正,就可能会造成不堪设想的后果。在网上书店电子商务平台中,我们以黑盒测试为主,白盒测试为辅。对关键模块采用白盒测试。测试结果:中文乱码问题,从数据库中取出的中文数据出现乱码。参数传递出错,无法传递数据。当大量用户同时对数据库进行访问时,效率低,有的用户访问失败。主要的解决方法:我使用如下方法来解决乱码问题:request.getParameter(choose).getBytes(8859_1),GB2312 对于各个模块接参数的格式进行了统一 本程序以中小型为基础,采用 JDBC 数据源进行连接数据库这就决定了本系统的先天缺陷。纯正的电子商务网站均采用连接池,出于技术难度大和资料缺乏放弃此最佳方案。第八章第八章 结束语结束语经过十个月的不懈努力,和指导老师的谆谆教导,以及同组同学的团结协作,充分利用大学四年所学的专业知识,通过大量阅读与设计相关的专业参考文献,我终于完成了本次毕业设计,已经基本上实现了网上书店系统的各项功能。在这次毕业设计过程中,我独立设计和实现了用户注册,用户登录,修改密码,留言板,书目浏览等五个模块的全部功能,以及这几个模块的数据库设计。通过这次毕业设计,我掌握了 SQLServer2000 这种大型数据库的编程方法,掌握了 JAVA语言和 JSP 技术。了解到电子商务的理论以及平台开发的模式,掌握了网络开发的方法与模式。对团队的协作,对软件开发方法和手段,有了一定的认识,丰富了我的软件开发的经验,提高了程序编写的水平,并加深理解了许多课程中、书本上学到的知识和理论。同时,通过编写毕业设计论文,我还基本掌握了软件文档的书写方法和书写格式。鲁迅说,世上倘若有完全的人,那么配活的也就相当有限。本系统尽管有自己的特色,如聊天室,游戏。但缺陷也是明显的,如安全性,效率问题等等。由于时间,能力,国内JAVA,JSP 技术资料有限等原因,有些功能实现的并不完美,在已经完成的程序中,也存在许多不尽人意的算法,也没有统一优化,系统有待进一步改善,而这些问题也让我充分认识到了软件开发的困难。通过毕业设计,我学会了如何去了解一种新型的技术,去掌握一种技术。以及软件开发的基本流程。在学习过程中,我们遇到问题经常上网求助,去书店查询资料,扩大了自己的知识面。总之,这次毕业设计为我今后继续学习、深造奠定了基础,我非常感谢各位老师、同学的支持与帮助。第九章第九章 附附 录录9 91 1 致谢致谢在本次毕业设计过程中,得到了指导老师的指导与支持。在此特别感谢 XX 老师、沈辉老师的大力帮助。指导老师的悉心指导和大力支持,在总体结构、功能的把握上给予了非常大的帮助,同时根我们提供了非常优越的设计环境,并对我在编程、数据库设计等细节工作上给予了耐心的指导,对于我们小组顺利完成这次毕业设计起到了关键性的作用。另外和我同组同学大家始终团结协作,努力拼搏,增强了我的团队意识,并且我们接下了深厚的友谊,我们自始至终在一种愉快的气氛中学习工作。此次毕业设计对提高我的编程技术、协调团队成员的关系等方面都由许多益处。在此我一并向他表示感谢。我还要感谢我的母校沈阳航空学院大学,以及在大学四年生活中给予我关心和帮助的老师和同学,是他们教会了我专业的知识和做人的道理。通过这次毕业设计我还明白了作为一名计算机专业的大学毕业生,我们要会的不仅仅是编写代码,更重要的是要有整体把握系统设计的能力。我会在以后的工作和学习中不断完善自己,为我最热爱的母校争光,为自己翻开辉煌的新篇章。9 92 2 参考文献参考文献1孙卫琴,李洪成.Tomcat 与 Java Web 开发技术详解.电子工业出版社,2003 年 6 月:1-2052BruceEckel.Java 编程思想. 机械工业出版社,2003 年 10 月:1-3783FLANAGAN.Java 技术手册. 中国电力出版社,2002 年 6 月:1-4654孙一林,彭波.Java 数据库编程实例. 清华大学出版社,2002 年 8 月:30-2105LEE ANNE PHILLIPS.巧学活用 HTML4.电子工业出版社,2004 年 8 月:1-3196飞思科技产品研发中心.JSP 应用开发详解.电子工业出版社,2003 年 9 月:32-3007耿祥义,张跃平.JSP 实用教程. 清华大学出版社,2003 年 5 月 1 日:1-3548孙涌.现代软件工程.北京希望电子出版社,2003 年 8 月:1-246 9萨师煊,王珊.数据库系统概论.高等教育出版社,2002 年 2 月:346010Brown 等.JSP 编程指南(第二版) . 电子工业出版社 ,2003 年 3 月:1-268 11清宏计算机工作室.JSP 编程技巧. 机械工业出版社, 2004 年 5 月:1-410 12朱红,司光亚.JSP Web 编程指南.电子工业出版社, 2001 年 9 月:34-307 13赛奎春.JSP 工程应用与项目实践. 机械工业出版社, 2002 年 8 月:23-294 9 93 3 部分源代码部分源代码(1)用户注册 userRegister,jsp:输入您的信息,带*号项必须填写:FORM action= Method=post登录名称*真实姓名* 设置密码* 电子邮件 * 联系电话*通信地址* jsp:setProperty name= login property=logname value= / jsp:setProperty name= login property=realname value= / jsp:setProperty name= login property=password value= / jsp:setProperty name= login property=email value= / jsp:setProperty name= login property=phone value= / jsp:setProperty name= login property=address value= / 本程序用了 Bean: Rigister.javamport java.sql.*;public class Register String logname, realname, password, email, phone, address; String message; Connection con; Statement sql; ResultSet rs; public Register() /加载桥接器: tryClass.forName(sun.jdbc.odbc.JdbcOdbcDriver); catch(ClassNotFoundException e)/添加记录到数据库的 user 表:public void addItem() try con=DriverManager.getConnection(jdbc:odbc:shop,); sql=con.createStatement(); String s= +logname+,+realname+,+password+,+ email+,+phone+,+address+; String condition=INSERT INTO user VALUES+(+s+); sql.executeUpdate(condition); message=注册成功了; con.close(); catch(SQLException e) message=你还没有注册,或该用户已经存在,请你更换一个名字; (2)用户登录 userLogin.jsp:输入用户名和密码:FORM action= Method=post登录名称输入密码 jsp:setProperty name= login property=logname value= / jsp:setProperty name= login property=password value= / 本程序用了 Bean: Login.java :package book;import java.sql.*;public class Login String logname, realname, password, phone, address; String success=false,message=; Connection con; Statement sql; ResultSet rs; public Login() /加载桥接器: tryClass.forName(sun.jdbc.odbc.JdbcOdbcDriver); catch(ClassNotFoundException e)/查询数据库的 user 表: public String getMessage() try con=DriverManager.getConnection(jdbc:odbc:shop,); sql=con.createStatement(); String condition= SELECT * FROM user WHERE logname = +logname+; rs=sql.executeQuery(condition); int rowcount=0; String ps=null; while(rs.next() rowcount+; logname=rs.getString(logname); realname=rs.getString(realname); ps=rs.getString(password); phone=rs.getString(phone); address=rs.getString(address); if(rowcount=1)&(password.equals(ps) message=ok; success=ok; else message=输入的用户名或密码不正确; success=false; con.close(); return message; catch(SQLException e) message=输入的用户名或密码不正确; success=false; return message; (3)修改密码 modifyPassword.jsp:String success=login.getSuccess(); if(success=null) success=; if(!(success.equals(ok) response.sendRedirect(userLogin.jsp); %修改密码,密码长度不能超过30个字符:FORM action= Method=post输入您的用户名:Input type=text name=logname value= 输入您的密码:输入您的新的密码:请再输入一次新密码:% String logname=request.getParameter(logname); /获取提交的用户名。 logname=getString(logname); String password=request.getParameter(password); /获取提交的密码。 password=getString(password); String newPassword1=request.getParameter(newPassword1); /获取提交的新密码1。 newPassword1=getString(newPassword1); String newPassword2=request.getParameter(newPassword2); /获取提交的新密码2。 newPassword2=getString(newPassword2); tryClass.forName(sun.jdbc.odbc.JdbcOdbcDriver); catch(ClassNotFoundException event) /验证身份: Connection con=null; Statement sql=null; boolean modify=false; boolean ifEquals=false; ifEquals=(newPassword1.equals(newPassword2)&(newPassword1.length()=30); if(ifEquals=true) try con=DriverManager.getConnection(jdbc:odbc:shop,); sql=con.createStatement(); boolean bo1=logname.equals(login.getLogname(), bo2=password.equals(login.getPassword(); if(bo1&bo2) /修改密码: modify=true; out.print(您的密码已经更新); String c=UPDATE user SET password = +newPassword1+ WHERE logname = +logname+; sql.executeUpdate(c); con.close(); catch(SQLException e1) else out.print(你两次输入的密码不一致或长度过大); if(modify=false&ifEquals=true) out.print(您没有输入密码帐号或您输入的帐号或密码不正确+logname+:+password); %(4)书目浏览 showBookList.jsp: 图书目录: %! /声明一个共享的连接对象: Connection con=null; /显示数据库记录的方法: public void showList(ResultSet rs,javax.servlet.jsp.JspWriter out,int n,String buybook) try out.print(); out.print(); out.print(+id+); out.print(+订购号+); out.print(+书名+); out.print(+作者+); out.print(+出版社+); out.print(+出版时间+); out.print(+价钱+); out.print(+分类+); out.print(+添加到订单+); out.print(); for(int i=1;i=n;i+) out.print(); String id=rs.getString(1);/图书id号。 out.print(+id+); out.print(+rs.getString(2)+); out.print(+rs.getString(3)+); out.print(+rs.getString(4)+); out.print(+rs.getString(5)+); out.print(+rs.getDate(6)+); out.print(+rs.getString(7)+); out.print(+rs.getString(8)+); /在本书的的后面显示一个表单,该表单将内容提交到buybook.jsp, /将id号提交给buybook.jsp,以便订购该书: String s1=; String s2=; String s3= ; String s=s1+s2+s3; out.print(+s+); out.print() ; rs.next(); out.print(); catch(Exception e1) % Form action= method=post 显示下一页: Form action= method=post 显示上一页: Form action= method=post 输入欲要显示的页 handlePage.getPageCount() n=1; handlePage.setShowPage(n); /显示该页。 out.print(目前显示第+handlePage.getShowPage()+页); /将游标移到: rs.absolute(n-1)*handlePage.getPageSize()+1); showList(rs,out,handlePage.getPageSize(),buybook); /显示第该页的内容。 else if(s.equals(previous) int n=handlePage.getShowPage(); /获取目前的页数。 n=(n-1); /将页数减1。 if(n本程序用了Bean: PageNumber.javapackage book;public class PageNumber int rowCount=1, /总的记录数。 pageSize=1, /每页显示的记录数。 showPage=1, /设置欲显示的页码数。 pageCount=1; /分页之后的总页数。 public void setRowCount(int n) rowCount=n; public int getRowCount() return rowCount; public void setPageCount(int r,int p) rowCount=r; pageSize=p; int n=(rowCount%pageSize)=0?(rowCount/pageSize):(rowCount/pageSize+1) ; pageCount=n; public int getPageCount() return pageCount; public void setShowPage(int n) showPage=n; public int getShowPage() return showPage; public void setPageSize(int n) pageSize=n; public int getPageSize() return pageSize; 5留言板 message.jsp:你可以在这里实现公共留言、私人留言。FORM action= method=post输入你的会员名字Input Type=text name=logname value=输入你的留言: 公共留言(所有的会员都能查看到):私人留言(输入他(她)的会员名)To:进行留言的文件 leaveword.jsp:% /获取提交键的的串值: String s=request.getParameter(submit); s=getString(s); /根据 s 的不同情况分开处理: if(s.equals(提交为公共留言) /获取提交的留言: String ms=request.getParameter(message); ms=getString(ms); publicbean.setLogname(login.getLogname(); publicbean.setMessage(+login.getLogname()+的留言:+ms); /留言: publicbean.addItem(); out.print(publicbean.getBackNews(); else if(s.equals(提交为私人留言) /获取会员的名字: String name=request.getParameter(person); name=getString(name); String ms=request.getParameter(message); ms=getString(ms); if(name.equals() out.print(您没有输入他(她)的名字,不能留言给人家); else secretbean.setLogname(name); secretbean.setMessage(+login.getLogname()+留言给你:+ms); /留言时间: long n=System.currentTimeMillis(); String time=String.valueOf(n); secretbean.setTime(time); /留言: secretbean.addItem(); out.print(secretbean.getBackNews(); 查看公共留言的文件 publicmessage.jsp: 公共留言列表: %! /声明一个共享的连接对象: Connection con=null; /显示数据库记录的方法: public void showList(ResultSet rs,javax.servlet.jsp.JspWriter out,int n,book.HandleMessage h) try out.print(); out.print(); out.print(+会员名+); out.print(+留言信息+); out.print(); for(int i=1;i=n;i+) String logname=rs.getString(logname); String message=rs.getString(public); if(logname=null) logname=; if(message=null) message=; /为了能显示原始的 HTML 或 JSP 文件格式的信息,需对信息进行回压流处理: h.setContent(message); message=h.getContent(); /将信息显示在表格中: out.print(); out.print(+logname+); out.print(+message+); out.print() ; rs.next(); out.print(); catch(Exception e1) % 输入欲要显示的页 负责公共留言的 beans publicword.java:/添加记录到数据库的 wordpad 表: public void addItem() try con=DriverManager.getConnection(jdbc:odbc:shop,); sql=con.createStatement(); String s=+logname+,+message+; String condition=INSERT INTO wordpad VALUES+(+s+); sql.executeUpdate(condition); backNews=添加成功了; con.close(); catch(SQLException e) /由于表 wordpad 和 member 表通过字段 logname 做了关联,所以如果输入的logname /不对,就会出现异常 backNews=你没有登录,不能留言;查看私人留言的文件 secretmessage.jsp: 公共留言列表: %! /声明一个共享的连接对象: Connection con=null; /显示数据库记录的方法: public void showList(ResultSet rs,javax.servlet.jsp.JspWriter out,int n,book.HandleMessage h) try out.print(); out.print(); out.print(+会员名+); out.print(+留言信息+); out.print(+留言时间+); out.print(+删除留言+); out.print(); for(int i=1;i=n;i+) String logname=rs.getString(logname); if(logname=null) logname=; String message=rs.getString(message); if(message=null) message=; String time =rs.getString(time); /获取该信息的留言时间 if(time=null) time=; /为了能显示原始的 HTML 或 JSP 文件格式的信息,需对信息进行流处理: h.setContent(message); message=h.getContent(); /将信息显示在表格中: out.print(); out.print(+logname+); out.print(+message+); out.print(+time+); /添加一个删除该信息的表单: String s1=; String s2=; String s3= ; String s=s1+s2+s3; out.print(+s+); out.print() ; rs.next(); out.print(); catch(Exception e1) % 输入欲要显示的页 负责私人留言的 beans secretword.java: /添加记录到数据库的 wordpad 表: /我们要求留言的时间是唯一的,所以下面的方法声明为 synchronized public synchronized void addItem() try con=DriverManager.getConnection(jdbc:odbc:shop,); sql=con.createStatement(); String s=+logname+,+message+,+time+; String condition=INSERT INTO secretwordpad VALUES+(+s+); sql.executeUpdate(condition); backNews=添加成功了; con.close(); catch(SQLException e) /由于表 wordpad 和 member 表通过字段 logname 做了关联,所以如果输入对方的logname /不存在,就会出现异常 backNews=该会员不存在,不能留言给他(她);删除私人留言的文件 delete.jsp:9 94 4 翻翻 译译The Java I/O SystemCreating a good input/output (I/O) system is one of the more difficult tasks for the language designer.This is evidenced by the number of different approaches. The challenge seems to be in covering all eventualities. Not only are there different sources and sinks of I/O that you want to communicate with (files, the console, network connections, etc.), but you need to talk to them in a wide variety of ways (sequential, random-SQLServer2000, buffered, binary, character, by lines, by words, etc.). The Java library designers attacked this problem by creating lots of classes. In fact, there are so many classes for Javas I/O system that it can be intimidating at first (ironically, the Java I/O design actually prevents an explosion of classes). There was also a significant change in the I/O library after Java 1.0, when the original byte-oriented library was supplemented with char-oriented, Unicode-based I/O classes. In JDK 1.4, the nio classes (for “new I/O,” a name well still be using years from now) were added for improved performance and functionality. As a result, there are a fair number of classes to learn before you understand enough of Javas I/O picture that you can use it properly. In addition, its rather important to understand the evolution history of the I/O library, even if your first reaction is “dont bother me with history, just show me how to use it!” The problem is that without the historical perspective, you will rapidly become confused with some of the classes and when you should and shouldnt use them.This chapter will give you an introduction to the variety of I/O classes in the standard Java library and how to use them.The File classBefore getting into the classes that actually read and write data to streams, well look at a utility provided with the library to assist you in handling file directory issues.The File class has a deceiving name; you might think it refers to a file, but it doesnt. It can represent either the name of a particular file or the names of a set of files in a directory. If its a set of files, you can ask for that set using the list( ) method, which returns an array of String. It makes sense to return an array rather than one of the flexible container classes, because the number of elements is fixed, and if you want a different directory listing, you just create a different File object. In fact, “FilePath” would have been a better name for the class. This section shows an example of the use of this class, including the associated FilenameFilter interface.A directory listerSuppose youd like to see a directory listing. The File object can be listed in two ways. If you call list( ) with no arguments, youll get the full list that the File object contains. However, if you want a restricted listfor example, if you want all of the files with an extension of .javathen you use a “directory filter,” which is a class that tells how to select the File objects for display.The DirFilter class “implements” the interface FilenameFilter. Its useful to see how simple the FilenameFilter interface is:public interface FilenameFilter boolean accept(File dir, String name);It says all that this type of object does is provide a method called accept( ). The whole reason behind the creation of this class is to provide the accept( ) method to the list( ) method so that list( ) can “call back” accept( ) to determine which file names should be included in the list. Thus, this structure is often referred to as a callback. More specifically, this is an example of the Strategy Pattern, because list( ) implements basic functionality, and you provide the Strategy in the form of a FilenameFilter in order to complete the algorithm necessary for list( ) to provide its service. Because list( ) takes a FilenameFilter object as its argument, it means that you can pass an object of any class that implements FilenameFilter to choose (even at run time) how the list( ) method will behave. The purpose of a callback is to provide flexibility in the behavior of code.DirFilter shows that just because an interface contains only a set of methods, youre not restricted to writing only those methods. (You must at least provide definitions for all the methods in an interface, however.) In this case, the DirFilter constructor is also created.The accept( ) method must accept a File object representing the directory that a particular file is found in, and a String containing the name of that file. You might choose to use or ignore either of these arguments, but you will probably at least use the file name. Remember that the list( ) method is calling accept( ) for each of the file names in the directory object to see which one should be included; this is indicated by the boolean result returned by accept( ).To make sure the element youre working with is only the file name and contains no path information, all you have to do is take the String object and create a File object out of it, then call getName( ), which strips away all the path information (in a platform-independent way). Then accept( ) uses a regular expression matcher object to see if the regular expression regex matches the name of the file. Using accept( ), the list( ) method returns an array.Input and outputI/O libraries often use the abstraction of a stream, which represents any data source or sink as an object capable of producing or receiving pieces of data. The stream hides the details of what happens to the data inside the actual I/O device.The Java library classes for I/O are divided by input and output, as you can see by looking at the class hierarchy in the JDK documentation. By inheritance, everything derived from the InputStream or Reader classes have basic methods called read( ) for reading a single byte or array of bytes. Likewise, everything derived from OutputStream or Writer classes have basic methods called write( ) for writing a single byte or array of bytes. However, you wont generally use these methods; they exist so that other classes can use themthese other classes provide a more useful interface. Thus, youll rarely create your stream object by using a single class, but instead will layer multiple objects together to provide your desired functionality. The fact that you create more than one object to create a single resulting stream is the primary reason that Javas stream library is confusing. Its helpful to categorize the classes by their functionality. In Java 1.0, the library designers started by deciding that all classes that had anything to do with input would be inherited from InputStream, and all classes that were associated with output would be inherited from OutputStream.Types of InputStreamInputStreams job is to represent classes that produce input from different sources. These sources can be: 1. An array of bytes. 2. A String object. 3. A file. 4. A “pipe,” which works like a physical pipe: You put things in at one end and they come out the other. 5. A sequence of other streams, so you can collect them together into a single stream. 6. Other sources, such as an Internet connection. (This is covered in Thinking in Enterprise Java.) Each of these has an associated subclass of InputStream. In addition, the FilterInputStream is also a type of InputStream, to provide a base class for decorator classes that attach attributes or useful interfaces to input streams. This is discussed later.Types of OutputStreamThis category includes the classes that decide where your output will go: an array of bytes (no String, however; presumably, you can create one using the array of bytes), a file, or a “pipe.” In addition, the FilterOutputStream provides a base class for decorator classes that attach attributes or useful interfaces to output streams.Adding attributes and useful interfacesThe use of layered objects to dynamically and transparently add responsibilities to individual objects is referred to as the Decorator pattern. (Patterns are the subject of Thinking in Patterns (with Java) at www.BruceE.) The decorator pattern specifies that all objects that wrap around your initial object have the same interface. This makes the basic use of the decorators transparentyou send the same message to an object whether it has been decorated or not. This is the reason for the existence of the “filter” classes in the Java I/O library: The abstract “filter” class is the base class for all the decorators. (A decorator must have the same interface as the object it decorates, but the decorator can also extend the interface, which occurs in several of the “filter” classes). Decorators are often used when simple subclassing results in a large number of classes in order to satisfy every possible combination that is neededso many classes that it becomes impractical. The Java I/O library requires many different combinations of features, and this is the justification for using the decorator pattern.There is a drawback to the decorator pattern, however. Decorators give you much more flexibility while youre writing a program (since you can easily mix and match attributes), but they add complexity to your code. The reason that the Java I/O library is awkward to use is that you must create many classesthe “core” I/O type plus all the decoratorsin order to get the single I/O object that you want.The classes that provide the decorator interface to control a particular InputStream or OutputStream are the FilterInputStream and FilterOutputStream, which dont have very intuitive names. FilterInputStream and FilterOutputStream are derived from the base classes of the I/O library, InputStream and OutputStream, which is the key requirement of the decorator (so that it provides the common interface to all the objects that are being decorated).Reading from an InputStream with FilterInputStreamThe FilterInputStream classes accomplish two significantly different things. DataInputStream allows you to read different types of primitive data as well as String objects. (All the methods start with “read,” such as readByte( ), readFloat( ), etc.) This, along with its companion DataOutputStream, allows you to move primitive data from one place to another via a stream. These “places” are determined by the classes in Table The remaining classes modify the way an InputStream behaves internally: whether its buffered or unbuffered, if it keeps track of the lines its reading (allowing you to ask for line numbers or set the line number), and whether you can push back a single character. The last two classes look a lot like support for building a compiler (that is, they were probably added to support the construction of the Java compiler), so you probably wont use them in general programming.Youll need to buffer your input almost every time, regardless of the I/O device youre connecting to, so it would have made more sense for the I/O library to make a special case (or simply a method call) for unbuffered input rather than buffered input.Writing to an OutputStream with FilterOutputStreamThe complement to DataInputStream is DataOutputStream, which formats each of the primitive types and String objects onto a stream in such a way that any DataInputStream, on any machine, can read them. All the methods start with “write,” such as writeByte( ), writeFloat( ), etc.The original intent of PrintStream was to print all of the primitive data types and String objects in a viewable format. This is different from DataOutputStream, whose goal is to put data elements on a stream in a way that DataInputStream can portably reconstruct them.The two important methods in PrintStream are print( ) and println( ), which are overloaded to print all the various types. The difference between print( ) and println( ) is that the latter adds a newline when its done. PrintStream can be problematic because it traps all IOExceptions (You must explicitly test the error status with checkError( ), which returns true if an error has occurred). Also, PrintStream doesnt internationalize properly and doesnt handle line breaks in a platform-independent way.Readers & WritersJava 1.1 made some significant modifications to the fundamental I/O stream library. When you see the Reader and Writer classes, your first thought (like mine) might be that these were meant to replace the InputStream and OutputStream classes. But thats not the case. Although some aspects of the original streams library are deprecated (if you use them you will receive a warning from the compiler), the InputStream and OutputStream classes still provide valuable functionality in the form of byte-oriented I/O, whereas the Reader and Writer classes provide Unicode-compliant, character-based I/O. In addition:1. Java 1.1 added new classes into the InputStream and OutputStream hierarchy, so its obvious those hierarchies werent being replaced. 2. There are times when you must use classes from the “byte” hierarchy in combination with classes in the “character” hierarchy. To accomplish this, there are “adapter” classes:InputStreamReader converts an InputStream to a Reader and OutputStreamWriter converts an OutputStream to a Writer. The most important reason for the Reader and Writer hierarchies is for internationalization. The old I/O stream hierarchy supports only 8-bit byte streams and doesnt handle the 16-bit Unicode characters well. Since Unicode is used for internationalization (and Javas native char is 16-bit Unicode), the Reader and Writer hierarchies were added to support Unicode in all I/O operations. In addition, the new libraries are designed for faster operations than the old. As is the practice in this book, I will attempt to provide an overview of the classes, but assume that you will use the JDK documentation to determine all the details, such as the exhaustive list of methods. Sources and sinks of dataAlmost all of the original Java I/O stream classes have corresponding Reader and Writer classes to provide native Unicode manipulation. However, there are some places where the byte-oriented InputStreams and OutputStreams are the correct solution; in particular, the java.util.zip libraries are byte-oriented rather than char-oriented. So the most sensible approach to take is to try to use the Reader and Writer classes whenever you can, and youll discover the situations when you have to use the byte-oriented libraries, because your code wont compile.Off by itself: RandomSQLServer2000FileRandomSQLServer2000File is used for files containing records of known size so that you can move from one record to another using seek( ), then read or change the records. The records dont have to be the same size; you just have to be able to determine how big they are and where they are placed in the file. At first its a little bit hard to believe that RandomSQLServer2000File is not part of the InputStream or OutputStream hierarchy. However, it has no association with those hierarchies other than that it happens to implement the DataInput and DataOutput interfaces (which are also implemented by DataInputStream and DataOutputStream). It doesnt even use any of the functionality of the existing InputStream or OutputStream classes; its a completely separate class, written from scratch, with all of its own (mostly native) methods. The reason for this may be that RandomSQLServer2000File has essentially different behavior than the other I/O types, since you can move forward and backward within a file. In any event, it stands alone, as a direct descendant of Object. Essentially, a RandomSQLServer2000File works like a DataInputStream pasted together with a DataOutputStream, along with the methods getFilePointer( ) to find out where you are in the file, seek( ) to move to a new point in the file, and length( ) to determine the maximum size of the file. In addition, the constructors require a second argument (identical to fopen( ) in C) indicating whether you are just randomly reading (“r”) or reading and writing (“rw”). Theres no support for write-only files, which could suggest that RandomSQLServer2000File might have worked well if it were inherited from DataInputStream. The seeking methods are available only in RandomSQLServer2000File, which works for files only. BufferedInputStream does allow you to mark( ) a position (whose value is held in a single internal variable) and reset( ) to that position, but this is limited and not very useful.Most, if not all, of the RandomSQLServer2000File functionality is superceded in JDK 1.4 with the nio memory-mapped files.Input streams1. Buffered input fileTo open a file for character input, you use a FileInputReader with a String or a File object as the file name. For speed, youll want that file to be buffered so you give the resulting reference to the constructor for a BufferedReader. Since BufferedReader also provides the readLine( ) method, this is your final object and the interface you read from. When you reach the end of the file, readLine( ) returns null so that is used to break out of the while loop. The String s2 is used to accumulate the entire contents of the file (including newlines that must be added since readLine( ) strips them off). s2 is then used in the later portions of this program. Finally, close( ) is called to close the file. Technically, close( ) will be called when finalize( ) runs, and this is supposed to happen (whether or not garbage collection occurs) as the program exits. However, this has been inconsistently implemented, so the only safe approach is to explicitly call close( ) for files.Section 1b shows how you can wrap System.in for reading console input. System.in is an InputStream, and BufferedReader needs a Reader argument, so InputStreamReader is brought in to perform the adaptation. 2. Input from memoryThis section takes the String s2 that now contains the entire contents of the file and uses it to create a StringReader. Then read( ) is used to read each character one at a time and send it out to the console. Note that read( ) returns the next byte as an int and thus it must be cast to a char to print properly.3. Formatted memory inputTo read “formatted” data, you use a DataInputStream, which is a byte-oriented I/O class (rather than char-oriented). Thus you must use all InputStream classes rather than Reader classes. Of course, you can read anything (such as a file) as bytes using InputStream classes, but here a String is used. To convert the String to an array of bytes, which is what is appropriate for a ByteArrayInputStream, String has a getBytes( ) method to do the job. At that point, you have an appropriate InputStream to hand to DataInputStream. If you read the characters from a DataInputStream one byte at a time using readByte( ), any byte value is a legitimate result, so the return value cannot be used to detect the end of input. Instead, you can use the available( ) method to find out how many more characters are available. Heres an example that shows how to read a file one byte at a time:/: c12:TestEOF.java/ Testing for end of file while reading a byte at a time.import java.io.*;public class TestEOF / Throw exceptions to console: public static void main(String args) throws IOException DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream(TestEOF.java); while(in.available() != 0) System.out.print(char)in.readByte(); /:Note that available( ) works differently depending on what sort of medium youre reading from; its literally “the number of bytes that can be read without blocking.” With a file, this means the whole file, but with a different kind of stream this might not be true, so use it thoughtfully. You could also detect the end of input in cases like these by catching an exception. However, the use of exceptions for control flow is considered a misuse of that feature. 4. File outputThis example also shows how to write data to a file. First, a FileWriter is created to connect to the file. Youll virtually always want to buffer the output by wrapping it in a BufferedWriter (try removing this wrapping to see the impact on the performancebuffering tends to dramatically increase performance of I/O operations). Then for the formatting its turned into a PrintWriter. The data file created this way is readable as an ordinary text file. As the lines are written to the file, line numbers are added. Note that LineNumberInputStream is not used, because its a silly class and you dont need it. As shown here, its trivial to keep track of your own line numbers. When the input stream is exhausted, readLine( ) returns null. Youll see an explicit close( ) for out1, because if you dont call close( ) for all your output files, you might discover that the buffers dont get flushed, so theyre incomplete. Output streamsThe two primary kinds of output streams are separated by the way they write data; one writes it for human consumption, and the other writes it to be reacquired by a DataInputStream. The RandomSQLServer2000File stands alone, although its data format is compatible with the DataInputStream and DataOutputStream. 5. Storing and recovering dataA PrintWriter formats data so that its readable by a human. However, to output data for recovery by another stream, you use a DataOutputStream to write the data and a DataInputStream to recover the data. Of course, these streams could be anything, but here a file is used, buffered for both reading and writing. DataOutputStream and DataInputStream are byte-oriented and thus require the InputStreams and OutputStreams. If you use a DataOutputStream to write the data, then Java guarantees that you can accurately recover the data using a DataInputStreamregardless of what different platforms write and read the data. This is incredibly valuable, as anyone knows who has spent time worrying about platform-specific data issues. That problem vanishes if you have Java on both platforms.When using a DataOutputStream, the only reliable way to write a String so that it can be recovered by a DataInputStream is to use UTF-8 encoding, accomplished in section 5 of the example using writeUTF( ) and readUTF( ). UTF-8 is a variation on Unicode, which stores all characters in two bytes. If youre working with ASCII or mostly ASCII characters (which occupy only seven bits), this is a tremendous waste of space and/or bandwidth, so UTF-8 encodes ASCII characters in a single byte, and non-ASCII characters in two or three bytes. In addition, the length of the string is stored in the first two bytes. However, writeUTF( ) and readUTF( ) use a special variation of UTF-8 for Java (which is completely described in the JDK documentation for those methods) , so if you read a string written with writeUTF( ) using a non-Java program, you must write special code in order to read the string properly. With writeUTF( ) and readUTF( ), you can intermingle Strings and other types of data using a DataOutputStream with the knowledge that the Strings will be properly stored as Unicode, and will be easily recoverable with a DataInputStream.The writeDouble( ) stores the double number to the stream and the complementary readDouble( ) recovers it (there are similar methods for reading and writing the other types). But for any of the reading methods to work correctly, you must know the exact placement of the data item in the stream, since it would be equally possible to read the stored double as a simple sequence of bytes, or as a char, etc. So you must either have a fixed format for the data in the file, or extra information must be stored in the file that you parse to determine where the data is located. Note that object serialization (described later in this chapter) may be an easier way to store and retrieve complex data structures. 6. Reading and writing random SQLServer2000 filesAs previously noted, the RandomSQLServer2000File is almost totally isolated from the rest of the I/O hierarchy, save for the fact that it implements the DataInput and DataOutput interfaces. So you cannot combine it with any of the aspects of the InputStream and OutputStream subclasses. Even though it might make sense to treat a ByteArrayInputStream as a random-SQLServer2000 element, you can use RandomSQLServer2000File only to open a file. You must assume a RandomSQLServer2000File is properly buffered since you cannot add that. The one option you have is in the second constructor argument: you can open a RandomSQLServer2000File to read (“r”) or read and write (“rw”). Using a RandomSQLServer2000File is like using a combined DataInputStream and DataOutputStream (because it implements the equivalent interfaces). In addition, you can see that seek( ) is used to move about in the file and change one of the values. With the advent of new I/O in JDK 1.4, you may want to consider using memory-mapped files instead of RandomSQLServer2000File. Piped streamsThe PipedInputStream, PipedOutputStream, PipedReader and PipedWriter have been mentioned only briefly in this chapter. This is not to suggest that they arent useful, but their value is not apparent until you begin to understand multithreading, since the piped streams are used to communicate between threads.Standard I/OThe term standard I/O refers to the Unix concept (which is reproduced in some form in Windows and many other operating systems) of a single stream of information that is used by a program. All the programs input can come from standard input, all its output can go to standard output, and all of its error messages can be sent to standard error. The value of standard I/O is that programs can easily be chained together, and one programs standard output can become the standard input for another program. This is a powerful tool. Reading from standard inputFollowing the standard I/O model, Java has System.in, System.out, and System.err. Throughout this book, youve seen how to write to standard output using System.out, which is already prewrapped as a PrintStream object. System.err is likewise a PrintStream, but System.in is a raw InputStream with no wrapping. This means that although you can use System.out and System.err right away, System.in must be wrapped before you can read from it.译文:译文:JavaJava I/OI/O 系统系统对编程语言的设计者来说,创建一套好的输入输出(I/O)系统,是一项难度极高的任务。这一点可以从解决方案的数量之多上看出端倪。这个问题难就难在它要面对的可能性太多了。不仅是因为有那么多 I/O 的源和目地(文件,控制台,网络连接等等),而且还有很多方法(顺序的sequential,随机的random-SQLServer2000,缓存的buffered,二进制的binary,字符方式的character,行的by lines,字的by words,等等)。 Java 类库的设计者们用创建很多类的办法来解决这个问题。坦率地说 Java I/O 系统的类实在是太多了,以至于初看起来会把人吓着(但是,具有讽刺意味的是,这种设计实际上是限制了类的爆炸性增长)。此外,Java 在 1.0 版之后又对其 I/O 类库作了重大的修改,原先是面向 byte 的,现在又补充了面向 Unicode 字符的类库。为了提高性能,完善功能,JDK 1.4又加了一个 nio(意思是new I/O。这个名字会用上很多年)。这么以来,如果你想对 Java的 I/O 类库有个全面了解,并且做到运用自如,你就得先学习大量的类。此外,了解 I/O 类库的演化的历史也是相当重要的。可能你的第一反应是别拿什么历史来烦我了,告诉我怎么用就可以了!但问题是,如果你对这段历史一无所知,很快就会被一些有用或是没用的类给搞糊涂了。 本章会介绍 Java 标准类库中的各种 I/O 类,及其使用方法。 FileFile 类类在介绍直接从流里读写数据的类之前,我们先介绍一下处理文件和目录的类。 File 类有一个极具欺骗性的名字;或许你会认为这是一个关于文件的类,但它不是。你可以用它来表示某个文件的名字,也可以用它来表示目录里一组文件的名字。如果它表示的是一组文件,那么你还可以用 list( )方法来进行查询,让它会返回 String 数组。由于元素数量是固定的,因此数组会比容器更好一些。如果你想要获取另一个目录的清单,再建一个 File对象就是了。实际上,叫它 FilePath可能会更好一些。下面我们举例说明怎样使用这个类及其相关的 FilenameFilter 接口。 目录列表器目录列表器假设你想看看这个目录。有两个办法。一是不带参数调用 list( )。它返回的是 File 对象所含内容的完整清单。但是,如果你要的是一个限制性列表(restricted list)的话 比方说,你想看看所有扩展名为.java 的文件 那么你就得使用目录过滤器了。这是一个专门负责挑选显示 File 对象的内容的类。DirFilter 实现了 FilenameFilter 接口。我们来看看 FilenameFilter 究竟有多简单: public interface FilenameFilter boolean accept(File dir, String name);也就是说,这类对象的任务就是提供一个 accept( )的方法。之所以要创建这个类,就是要给 list( )提供一个 accept( )方法,这样当 list( )判断该返回哪些文件名的时候,能够回过头来调用accept( )方法。因此,这种结构通常被称为回调(callback)。更准确地说,由于 list( )实现了基本功能,而 FilenameFilter 提供了对外服务所需的算法,因此这是一种策略模式(Strategy Pattern)。由于 list( )拿 FilenameFilter 对象当参数,因此你可以将任何实现 FilenameFilter 接口的对象传给它,并以此(甚至是在运行时)控制 list( )的工作方式。回调能提高程序的灵活性。 DirFilter 还告诉我们,interface 只是包含了一些方法,它没说你只能写这些方法。(但是,你至少要定义接口里有的方法。) 这里我们还定义了 DirFilter 的构造函数。 accept( )方法需要两个参数,一个是 File 对象,表示这个文件是在哪个目录里面的;另一个是 String,表示文件名。虽然你可以忽略它们中的一个,甚至两个都不管,但是你大概总得用一下文件名吧。记住,list( )会对目录里的每个文件调用 accept( ),并以此判断是不是把它包括到返回值里;这个判断依据就是 accept( )的返回值。 切记,文件名里不能有路径信息。为此你只要用一个 String 对象来创建 File 对象,然后再调用这个 File 对象的 getName( )就可以了。它会帮你剥离路径信息(以一种平台无关的方式)。然后再在 accept( )里面用正则表达式(regular expression)的 matcher 对象判断,regex 是否与文件名相匹配。兜完这个圈子,list( )方法返回了一个数组。输入与输出输入与输出I/O 类库常使用流(stream)这种抽象。所谓流是一种能生成或接受数据的,代表数据的源和目标的对象。流把 I/O 设备内部的具体操作给隐藏起来了。 正如 JDK 文档所显示的,Java 的 I/O 类库分成输入和输出两大部分。所有 InputStream 和Reader 的派生类都有一个基本的,继承下来的,能读取单个或 byte 数组的 read( )方法。同理,所有 OutputStream 和 Writer 的派生类都有一个基本的,能写入单个或 byte 数组的write( )方法。但通常情况下,你是不会去用这些方法的;它们是给其它类用的 而后者会提供一些更实用的接口。因此,你很少会碰到只用一个类就能创建一个流的情形,实际上你得把多个对象叠起来,并以此来获取所需的功能。Java 的流类库之所以会那么让人犯晕,最主要的原因就是你必须为创建一个流而动用多个对象。 我们最好还是根据其功能为这些 class 归个类。Java 1.0 的类库设计者们是从决定让所有与输入相关的类去继承 InputStream入手的。同理,所有与输出相关的类就该继承OutputStream 了。 InputStreamInputStream的种类的种类InputStream 的任务就是代表那些能从各种输入源获取数据的类。这些源包括: 1. byte 数组 2. String 对象 3. 文件 4. 类似流水线的管道(pipe)。把东西从一头放进去,让它从另一头出来。 5. 一个流的序列(A sequence of other streams),可以将它们组装成一个单独的流。 6. 其它源,比如 Internet 的连接。 (这部分内容在 Thinking in Enterprise Java 中讨论。 ) 这些数据源各自都有与之相对应的 InputStream 的子类。此外,FilterInputStream 也是InputStream 的子类,其作用是为基类提供decorator(修饰)类,而 decorator 又是为InputStream 配置属性和接口的。这部分内容我们以后再谈。 OutputStreamOutputStream的种类的种类这部分都是些决定往哪里输出的类:是 byte 的数组(不能是 String;不过你可以根据 byte数组创建字符串)还是文件,或者是管道。 此外,FilterOutputStream 还是 decorator 类的基类。它会为 OutputStream 安装属性和适用的接口。添加属性与适用的接口添加属性与适用的接口使用分层对象(layered objects),为单个对象动态地,透明地添加功能的做法,被称为Decorator Pattern。(模式是 Thinking in Patterns (with Java)的主题。)Decorator 模式要求所有包覆在原始对象之外的对象,都必须具有与之完全相同的接口。这使得decorator 的用法变得非常的透明-无论对象是否被 decorate 过,传给它的消息总是相同的。这也是 Java I/O 类库要有filter(过滤器)类的原因:抽象的filter类是所有 decorator的基类。(decorator 必须具有与它要包装的对象的全部接口,但是 decorator 可以扩展这个接口,由此就衍生出了很多filter类)。 Decorator 模式常用于如下的情形:如果用继承来解决各种需求的话,类的数量会多到不切实际的地步。Java 的 I/O 类库需要提供很多功能的组合,于是 decorator 模式就有了用武之地。 但是 decorator 有个缺点,在提高编程的灵活性的同时(因为你能很容易地混合和匹配属性),也使代码变得更复杂了。Java 的 I/O 类库之所以会这么怪,就是因为它必须为一个I/O 对象创建很多类,也就是为一个核心I/O 类加上很多 decorator。 为 InputStream 和 OutputStream 定义 decorator 类接口的类,分别是 FilterInputStream和 FilterOutputStream。这两个名字都起得不怎么样。FilterInputStream 和FilterOutputStream 都继承自 I/O 类库的基类 InputStream 和 OutputStream,这是decorator 模式的关键(惟有这样 decorator 类的接口才能与它要服务的对象的完全相同)。 用用FilterInputStreamFilterInputStream读取读取InputStreamInputStreamFilterInputStream 及其派生类有两项重要任务。DataInputStream 可以读取各种 primitive及 String。(所有的方法都以read打头,比如 readByte( ), readFloat( )。它,以及它的搭档 DataOutputStream,能让你通过流将 primitive 数据从一个地方导到另一个地方。这些地方都列在表 12-1 里。 其它的类都是用来修改 InputStream 的内部行为的:是不是做缓冲,是不是知道它所读取的行信息(允许你读取行号或设定行号),是不是会弹出单个字符。后两个看上去更像是给编译器用的(也就是说,它们大概是为 Java 编译器设计的),所以通常情况下,你是不大会用到它们的。 不论你用哪种 I/O 设备,输入的时候,最好都做缓冲。所以对 I/O 类来说,比较明智的做法还是把不缓冲当特例(或者去直接调用方法),而不是像现在这样把缓冲当作特例。用用FilterOutputStreamFilterOutputStream往往OutputStreamOutputStream里面写东西里面写东西DataInputStream 的另一半是 DataOutputStream。它的任务是把 primitive 数据和 String对象重新组织成流,这样其它机器就能用 DataInputStream 读取这个流了。DataOutputStream 的方法都是以write开头的,比如 writeByte( ),writeFloat( )等等。PrintStream 的用意是要以一种大家都能看懂的方式把 primitive 数据和 String 对象打印出来。这一点同 DataOutputStream 不同,后者是要将数据装入一个流,然后再交给 DataInputStream 处理。PrintStream 的两个最重要的方法是 print( )和 println( )。这两个方法都已经作了重载,因此可以打印各种数据。print( )和 println( )的区别在于,后者会多打印一个换行符。 使用 PrintStream 的时候会比较麻烦,因为它会捕捉所有的 IOException(所以你必须直接调用 checkError( )来检查错误条件,因为这个方法会在碰到问题的时候返回 true)。再加上,PrintStream 的国际化做得也不好,而且还不能以与平台无关的方式处理换行。ReaderReader 和和 WriterWriter类系类系Java 1.1 对最底层的 I/O 流类库作了重大修改。第一次看到 Reader 和 Writer 的时候,你会觉得它们大概是用来取代 InputStream 和 OutputStream 的 (和我一样)。但事实并非如此。虽然 InputStream 和 OutputStream 的某些功能已经淘汰了(如果你继续使用,编译器就会发警告),但它们仍然提供了很多很有价值的,面向 byte 的 I/O 功能,而 Reader 和 Writer 则提
- 温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

人人文库网所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。