【毕业设计】基于用JSP技术来组建企业内部信息管理网站

【获取】
http://mtw.so/pwd/6fSSgK
密码:123456

摘  要

随着计算机科学的发展,数据库技术在Internet和Intranet中的应用越来越广泛,为广大网络用户提供了更加周到和人性化的服务。本文描述了如何使用JSP技术来组建企业内部信息管理网站。实现了:员工信息的发布与共享,本文中的员工信息管理系统主要是实现员工资料的录入、信息的查询、记录和管理。作为人事管理系统和企业内网的一部分,企业员工信息管理系统可以便于企业领导掌握人员的动向,及时调整人才的分配;企业内部财务信息的发布与共享,本文中的企业内部财务信息查询管理系统通过对企业进出流水帐后台数据库的管理,实现了企业内部各种财务信息的管理,并可以生成各种类型的报表,便于管理层决策;员工之间的信息交流,本文中的内部信息交流系统可以实现企业内部通知的发布、各种具体问题的意见发布并获得相应的反馈。本文首先阐述了基于JSP平台的办公信息管理系统管理信息系统的开发背景以及其实践意义,其次说明了办公信息管理系统管理信息系统的功能以及相比同类系统的创新之处。然后就办公信息管理系统管理系统开发中所使用的一些的技术进行研究探讨。主要针对数据库的设计技术、存储过程技术、J2EE技术以及用SQL Server JSP 数据提供程序访问SQLserver2000数据库技术四个方面进行了研究。最后还附上了办公信息管理系统管理信息系统的安装说明、简单使用说明和一些通用性的经典代码。笔者化了大量的时间用于程序设计,这也是笔者工作的重点,所开发的系统具有实用价值,所编写的代码对J2EE程序员也有很好的参考性。在系统的开发过程中,笔者深刻体会到了J2EE平台的强大性、优越性以及存储过程在提高数据访问性能和增强数据访问安全性上所起到的重要作用。此外,对于关系代数在数据库科学里的应用,笔者在编程过程中也做了一定的研究。
关键词: 数据库;JSP;J2EE;存储过程;SQL Server 数据提供程序

目 录

摘要…
ABSTRACT…
1系统开发背景以及主要内容阐述…
2系统概述…
2.1系统提供的功能…
2.2系统一些新特点…
3系统设计过程及原理阐述…
3.1数据库设计 …
3.1.1数据库设计重点…
3.1.2规范化设计…
3.1.3数据库完整性设计…
3.1.4数据库的保护…
3.2使用存储过程…
3.3JSP平台概述…
3.4 J2EE技术探讨…
3.4.1J2EE概述…
3.4.2J2EE访问数据的基本方法…
3.4.3使用J2EE访问SQLserver2000 …
4系统使用说明…
4.1环境要求…
4.2系统的安装…
4.3常见操作…
5程序源代码经典部分选录…
5.1实现员工信息管理系统…
5.2企业财务管理系统的实现…
5.3企业内部信息交流系统的实现…
毕业设计成果…
致谢…
参考文献…

1 系统开发背景以及主要内容阐述

随着当今社会的迅猛发展,知识变的越来越重要,终身学习的观念已经深入人心。而办公信息管理系统――这一传统的获取知识的场所,它的地位也变的越来越重要。而办公信息管理系统的管理方法也更新了很多次。从最初的手工管理到现在的计算机管理等等。
笔者经过调查一些办公信息管理系统的现状,发现各办公信息管理系统使用的管理系统基本都是几年前的产品,大多使用jsp方式,web平台也主要使用jsp或php开发。而且以前的VB面向对象化编程(OOP)支持的不是很好,系统维护起来也相当困难。
MicrosoftJ2EE技术的推出,将计算带入一个新时代。现在J2EE已经引起业界广泛的关注。J2EE是专门为程序员设计的、功能强大的开发工具,利用该工具能够构建各类应用程序。J2EE可以说是博大精深,蕴含者丰富的新技术新思想。
J2EE使应用程序的功能更强大,使系统开发更简单,使系统的部署更轻松。而J2EE包含的统一的类库,统一的数据结构使得各类编程模型更统一。
笔者个人对J2EE技术非常感兴趣,在这方面也做过大量的研究。又鉴于当前流行的办公信息管理系统管理信息系统技术都比较陈旧,就萌发了用J2EE开发一个新办公信息管理系统管理信息系统的想法。
很高兴它成为为我毕业设计研究的课题。	
系统的实践意义有两个:1开发出的系统功能强大,可以应用于各大中型办公信息管理系统使用,可以根据数据的要求添加功能。2由于J2EE推出的时间不算很长,所以网上很少有用J2EE开发的公开源代码的大型系统。本系统可以给广大的J2EE编程爱好者一些参考。
本文理论部分主要针对数据库设计技术、存储过程技术、J2EE技术以及用SQL Server JSP 数据提供程序访问SQLserver2000数据库技术这四个方面进行了研究和探讨。

办公信息管理系统管理信息系统的每一行代码都是精雕细琢出来的,从里面体现出J2EE的强大性以及优越性。笔者在编程过程中查阅了大量的籍,参考了大量MSDN以及各大网站的技术文章,全部代码约有一万两千行左右。笔者为此做了大量的工作。
在系统的开发过程中,笔者深刻体会到了J2EE平台的强大性以及优越性以及存储过程在提高数据访问性能和增强数据访问安全性上所起到的重要作用。
2

系统概述

办公信息管理系统管理系统基于Microsoft公司最新的JSP平台构建,编码的基本语言是JSP。开发过程中统一使用J2EE框架的数据类型、方法,抛弃了原来vb6的内容。充分体现了J2EE的优越性,使系统易安装部署、易维护。
系统使用J2EE+SQLserver2000模式,数据层基本都基于存储过程构建,使得速度更快、安全性更高。

2.1系统提供的功能:

本设计的学习目的旨在通过对公司办公管理系统(B/S结构)的需求分析、任务概述、前台设计、数据库设计、模块实现的介绍,使得读者能够对用Java/JSP开发B/S结构的实用系统有一个清楚的认识和理解。同时让读者能够在阅读和自行动手实现的过程中,进一步理解如何由实际功能需求转化为具体Java编程,并让读者熟悉和掌握JSP / Servlet编程和Java数据库编程。本设计的学习重点是如何将企业内部办公管理中的实际问题提炼为功能需求,如何将功能需求转化为具体的B/S结构的模块设计和数据库设计,以及如何将系统设计转换为规范文档描述和标准Java代码实现。

设计简介:

本系统为公司办公信息管理系统,主要用来管理公司的员工信息和财务信息,并提供公司内部信息交流平台。该系统主要由以下四个部分组成:
1.系统用户身份验证子系统:对用户所输入的用户名和密码进行匹配,并限制用户登录错误的次数,同时记录用户的登录状态,以便在用户浏览系统的其他页面时,进行登录状态的确认。
2.公司员工信息管理子系统:除了对员工信息的查询外,还可以具体细化为用户修改个人信息页面,系统管理员页面,添加新用户页面和修改某个用户信息页面。
3.公司财务信息管理子系统:可以具体细化为添加新财务信息记录页面,添加新财务项目页面,生成各种财务报表页面和修改某个财务记录页面。
4.公司内部信息交流子系统:可以具体细化为通知公告牌页面,发布新通知页面,修改某个通知页面,意见箱页面,意见分析页面,投票站页面和投票分析页面。
5.
针对数据设计的部分:
由于数据的多元性和位置不确定性,该部分采取基于B/S的方式实现。代码使用JSP编写,利用JSP的优点,可以自动适应多种数据浏览器。截图如下:
数据只需要有一台联网的计算机和一个常用WEB浏览器。就可以轻松的进行办公信息管理系统查询、更改个人信息、向办公信息管理系统反馈信息等。该部分主要提供以下功能:
1.登陆验证。(防止数据信息被盗用。)
2.办公信息管理系统查询。(一个综合的办公信息管理系统查询系统,可以方便的使数据查到需要的籍。)
3.数据个人信息查询以及管理。(可以适当的更改一些数据个人的资料,如email等,此外在这里还可以查到数据当前的、所有的记录等。)
4.信息服务。(定期公布超期的数据列表,以及新到的办公信息管理系统等信息。)
2.2系统创新部分以及一些特点
1)首先本系统是基于J2EE平台构建的,这是以前从未有过的。
2)系统很好的解决了一个关于时间冲突的问题。
时间冲突问题阐述如下:
办公信息管理系统管理信息系统是一个网络版的系统,其运作方式是有一台主数据服务器、还有若干个负责各项功能的数据端。举个例子:办公信息管理系统可能有若干台数据端电脑用于管理、还可能有若干台用于管理、还可能有若干台用于办公信息管理系统、数据信息维护等。因为每台电脑的系统时间可能会发生改变,这就会造成数据错误。比如张某于2月10日在负责的A号电脑上借了一本,可能A的系统时间被误设定为2月5日。如果张某的最大时间为一个月,则他应该的时间就被误设定为3月5日。
笔者在开发过程中也参考了一些相关的办公信息管理系统系统,发现有的系统根本没有注意到这个问题。有的是在系统数据端设定一个时间校准的提示或者干脆就手工输入时间。这样无疑给操作人员增加了负担,而且校准还不一定正确。
在本系统中,所有的时间都是基于服务器时间的。即系统中必要的与时间有关的操作。都采用标准的T-SQL函数GETDATE()从数据服务器返回时间。这就避免了功能上的错误,也避免了给操作人员带来的不必要负担。
3)用J2EE的开放式并发进行并发控制
在办公信息管理系统系统的使用过程中,可能同时有多台数据机在操作同一个数据行。比如负责修改办公信息管理系统信息的A号电脑正在修改编号为XXX的籍,而编号为B的电脑正试图删除编号为XXX的籍。这样做肯定会有一些冲突,这就要讨论并发控制。
当多个用户试图同时修改数据时,需要建立控制机制来防止一个用户的修改对同时操作的其他用户所作的修改产生不利的影响。处理这种情况的系统叫做“并发控制”。
在以前的编程模型中,大多使用保守式并发控制,即在从获取记录直到记录在数据库中更新的这段时间内,该行对用户不可用。J2EE的数据集DataSet是一个断开式的模型,不适合保守式并发。在我所编写的办公信息管理系统管理信息系统中,使用了开放式并发控制(参见附录中我翻译的英文文章),即只有当实际更新数据时,该行才对其他用户不可用。更新将在数据库中检查该行并确定是否进行了任何更改。如果试图更新已更改的记录,则将导致并发冲突。
4)全部数据层都基于存储过程构建
使用存储过程,可以减少网络流量,提高程序的速度以及安全性。具体内容请参见笔者文章里对存储过程的研究讨论。

3系统设计过程及原理阐述
管理信息系统(以下简称MIS)服务于现代化的企事业管理,是提供企事业工作效率和经济效益的计算机网络系统。
管理信息系统涉及的因素非常多、非常复杂,开发起来具有一定的难度。如果掌握了一套行之有效的开发方法,以及把握好MIS开发中的重点,开发中就可以大量的解约人力、财力等。
我个人经过大量的研究、实践。认为在MIS开发中,首先数据库技术是MIS开发中的重要技术。数据库开发成败直接影响到整个MIS的开发。所以,构架一个优秀的MIS一定要有好的数据库设计。本文讨论的重点就是数据库设计理论。主要是两方面,一是基本的数据库理论;二是J2EE平台上的J2EE数据访问技术。
其次,在MIS开发过程中,所使用的开发工具和应开发应用程序的种类也很重要。这里就不能不提到Microsoft公司的JSP平台。JSP 是一种新的计算平台,它简化了在高度分布式 Internet 环境中的应用程序开发。它提供一个一致的面向对象的编程环境、提供一个将系统部署和版本控制冲突最小化的代码执行环境等等非常优秀的特点。在以后介绍开发过程中将简单阐述。
再次,界面的设计也是MIS的一个重点。界面一定要具有易学性及易使用性。在当今流行的程序设计中,设计包含用户界面的应用程序时有两种选择:Windows 窗体和 Web 窗体。两者在开发环境中都具有完全的设计时支持,并且可以提供丰富的用户界面和高级应用程序功能以解决业务问题。要根据应用程序的具体功能来选择到底开发何种应用程序。我所开发的这个办公信息管理系统管理信息系统是这两者的结合。在管理功能方面,我使用了传统的WinForms技术。而在数据使用方面的功能模块,是用webForms开发的。

3.1 数据库设计

	数据库技术是20世纪60年代后期产生何发展起来的一项计算机数据管理技术,现广泛运用与各种信息处理以及科学研究上。数据库技术已经成为当今时代非常重要的技术。
	当今流行的数据库系统主要是以关系数据库为代表的第二代数据库系统。
	当今流行的大型数据库管理系统主要有SQL Server、Oracle、Sybase等。
办公信息管理系统管理信息系统选用的是SQLserver2000数据库管理系统。
	选择它的原因有:SQLserver2000功能强大,能完整实现数据库系统的所有功能。再者,我们选用的系统开发平台是微软公司的JSP平台,它很好的支持了其公司的数据库产品SQLserver2000,而且为了加快数据处理速度,JSP平台中还专门有一个SQL Server数据提供程序(System.Data.SqlClient)。
办公信息管理系统管理信息系统使用SQLserver2000数据库管理系统,最后设计的数据库表如下:
数据库名称lib2004
数据表有:
管理员表(manager)
名称	类型	长度	说明
Man_id	nvarchar	50	管理员账号(主键)
Man_pwd	nvarchar	12	管理员密码(not null)
Man_purview	nvarchar	10	管理员权限(not null)

办公信息管理系统信息表(libInfo)存放办公信息管理系统信息,只有一条记录
字段名称	类型	长度	说明
No	Int	4	等于1
Lib_name	nvarchar	50	办公信息管理系统名称
Lib_org	nvarchar	50	隶属单位
Lib_tel	nvarchar	50	电话号码
Lib_adr	Nvarchar	100	详细地址

办公信息管理系统表(book) 
字段名称	类型	长度	说明
Book_id	Int	4	办公信息管理系统编号(自动增长) unique约束
Book_code	nvarchar	50	条码号(主键)
Book_name	nvarchar	50	办公信息管理系统题名(not null)
Book_pub	nvarchar	50	出版社
Book_isbn	nvarchar	50	ISBN号
Book_pubdate	smalldatetime	4	出版日期
Book_author	nvarchar	50	办公信息管理系统作者
Book_page	Int	4	办公信息管理系统页数
Book_price	money	8	办公信息管理系统价格
Book_adddate	smalldatetime	4	入馆日期
Book_place	nvarchar	50	存放位置(外部键- place. Book_place)
Book_sort	nvarchar	50	办公信息管理系统分类(外部键- booksort. Book_sort)
Book_remarks	nvarchar	4000	备注

数据表(au)
字段名称	字段类型	长度	说明
Au_serial	int	4	数据序号(自动增长) unique约束
Au_id	nvarchar	50	证号(主键)
Au_name	nvarchar	50	数据姓名
Au_sex	nvarchar	2	数据性别(只能为‘男’或‘女’)
Au_sort	nvarchar	50	数据类别(外部键- ausort.Au_sort)
Au_adddate	smalldatetime	4	添加日期
Au_adr	nvarchar	50	数据地址
Au_password	nvarchar	12	数据密码(12)
Au_email	nvarchar	50	数据email
Au_remarks	nvarchar	4000	数据详细资料

情况表(borrow)
字段名称	字段类型	长度	说明
Number	int	4	编号(自动编号 主键)
Au_id	nvarchar	50	数据编号(外部键-au.Au_id)
book_code	nvarchar	50	办公信息管理系统编号(外部键-book.book_code)
Borrow_date	smalldatetime	4	日期(not null)
Should_date	smalldatetime	4	应归还日期(not null)
Return_date	smalldatetime	4	归还日期
forfeit	money	4	罚款金额


办公信息管理系统存放位置(place)
字段名称	字段类型	字段长度	说明
Book_place	nvarchar	50	存放位置(主键)
Place_remarks	nvarchar	4000	存放位置具体说明

办公信息管理系统分类(booksort)
字段名称	字段类型	字段长度	说明
Book_sort	nvarchar	50	办公信息管理系统类型(主键)
Sort_remarks	nvarchar	4000	分类具体说明

数据分类(ausort)
字段名称	字段类型	长度	说明
Au_sort	nvarchar	50	数据类型(主键)
Au_borrowdays	Int	4	最长时间
Au_borrowbooks	Int	4	最大办公信息管理系统数

证挂失(aulost)
字段名称	字段类型	字段长度	说明
Lost_id	nvarchar	50	挂失的数据编号 主键
Lost_date	smalldatetime	4	挂失时间

办公信息管理系统损坏赔偿 (booklost)
字段名称	字段类型	字段长度	说明
Number	Int	4	编号(自动增加,主键)
Au_id	nvarchar	50	丢失办公信息管理系统的数据编号
Book_name	nvarchar	50	办公信息管理系统名称
Book_isbn	nvarchar	50	ISBN
Lost_money	Money	8	赔偿金额

数据库表关系如下:

以下我们讨论数据库设计方法时均以办公信息管理系统管理信息系统数据库(lib2004)为例.
3.1.1数据库设计重点
(1) 数据规范化
(2) 数据完整性
(3) 数据库的保护

3.1.2规范化设计

良好的数据规范可以减少数据冗余和一些插入异常和删除异常。使关系模式尽量满足3NF。规范化设计的内容比较多,在这里就不一一阐述。请详细体会lib2004数据库中每个表的构建。如在这方面想有进一步研究的化,请参阅一些数据库原理与技术方面的籍。

3.1.3数据库完整性设计

数据库完整性共分三类

(1) 实体完整性规则
实体完整性规则是指主关键字的任何部分不能为空值
比如在办公信息管理系统表(book)中
办公信息管理系统表(book)
字段名称 类型 长度 说明
Book_id Int 4 办公信息管理系统编号(自动增长) unique约束
Book_code nvarchar 50 条码号(主键)
Book_name nvarchar 50 办公信息管理系统题名(not null)
条码号(Book_code)是主关键字,其值就不能够为空。
主关键字不一定由一个字段组成,可以是多个字段的组合。
(2)引用完整性,又称参照完整性,主要是描述存在关系间引用时,不能引用不存在的元组.
图3-2
比如在办公信息管理系统分类表(booksort)与办公信息管理系统表(book)之间的关系(如图3-2),这是一个典型的一对多关系。关系的主键方是booksort表中的Book_sort(办公信息管理系统类别)字段,关系的外键方是book表中的Book_code(办公信息管理系统类别)字段。
其引用完整性就是book表中的每一本的办公信息管理系统类别Book_sort或者为空值,或等于办公信息管理系统分类表(booksort)中某行的Book_sort值。
通俗的说法就是办公信息管理系统不能属于一个没有定义的类别。
(3)用户自定义完整性
这是一种比较有针对性的完整性,由具体环境决定。例如:在数据表(au)中,数据的性别字段(Au_sex)的值必须为‘男’或‘女’。这就是一条用户自定义完整性规则。
这类完整性在SQLserver2000中的实现就是对相关表建一个check约束即可。比如在au表中建立一个CK_au约束,其约束表达式为([Au_sex] = ‘男’ or [Au_sex] = ‘女’),就实现了值必须为‘男’或‘女’的用户自定义完整规则。
3.1.4数据库的保护
数据库的保护主要内容是数据库的备份恢复、数据的事务性、以及如何进行并发控制。其中备份和恢复容易理解,这里主要阐述其它两项。
(1) 事务是一组操作序列.但是从用户的角度看来,事务是一个不可分割的操作序列。事务中的操作要么都做,要么都不做.事务不应该丢失,不应该被分割完成。
举个例子,从某个银行帐户向另一个帐户转入资金。这个过程分两步,首先将资金从一个帐户扣除,然后转入另一帐户。这个过程中,如果资金扣除以后由于一些因素导致失败。则资金就从一个帐户上扣除但没有转到另一个帐户上,就导致了两个用户都失去了这笔资金。如果将这两步组成一个事务,充分利用事务的共进共退性就可以避免这一点。
SQLserver2000事务语句主要包括BEGIN TRANSACTION(开始一个事务),COMMIT TRANSACTION(提交事务),ROLLBACK TRANSACTION(回滚事务)。
(2)数据库并发控制:在办公信息管理系统管理信息系统中,同时可能有多个数据端在进行数据操作。当多个用户试图同时修改数据时,需要建立控制机制来防止一个用户的修改对同时操作的其他用户所作的修改产生不利的影响。处理这种情况的系统叫做“并发控制”。处理并发的技术主要是封锁。J2EE数据结构基于断开的数据,使用开放式并发。
3.2 使用存储过程
在使用 SQL Server 2000 创建应用程序时,T-SQL 编程语言是应用程序和 SQL Server 数据库之间的主要编程接口。使用 T-SQL 程序时,可用两种方法存储和执行程序。可以在本地存储程序,并创建向 SQL Server 发送命令并处理结果的应用程序;也可以将程序在 SQL Server 中存储为存储过程,并创建执行存储过程并处理结果的应用程序。
SQL Server 中的存储过程与其它编程语言中的过程类似,原因是存储过程可以:
接受输入参数并以输出参数的形式将多个值返回至调用过程或批处理。
包含执行数据库操作(包括调用其它过程)的编程语句。
向调用过程或批处理返回状态值,以表明成功或失败(以及失败原因)。
使用 SQLServer 中的存储过程而不使用存储在数据计算机本地的 Transact-SQL 程序的优点有:
允许模块化程序设计。
只需创建过程一次并将其存储在数据库中,以后即可在程序中调用该过程任意次。存储过程可由在数据库编程方面有专长的人员创建,并可独立于程序源代码而单独修改。
允许更快执行。
如果某操作需要大量 T-SQL 代码或需重复执行,存储过程将比 T-SQL 批代码的执行要快。将在创建存储过程时对其进行分析和优化,并可在首次执行该过程后使用该过程的内存中版本。每次运行 T-SQL 语句时,都要从数据端重复发送,并且在SQL Server每次执行这些语句时,都要对其进行编译和优化。
减少网络流量。
一个需要数百行 T-SQL 代码的操作由一条执行过程代码的单独语句就可实现,而不需要在网络中发送数百行代码。
可作为安全机制使用。
即使对于没有直接执行存储过程中语句的权限的用户,也可授予他们执行该存储过程的权限。
此外在web编程方面,存储过程在安全问题上还可以防止动态SQL漏洞攻击,笔者经过一些调查,发现现在很多网站都有动态sql漏洞。只需要将密码字段的值设定为(’ or ‘1’='1)即可使用该网站的管理功能。
我所开发的办公信息管理系统管理信息系统,无论在windows窗体编程和jsp Web编程上都使用存储过程与数据库交互。
3.3 JSP平台概述
办公信息管理系统管理信息系统的开发是基于JSP平台的,所有在这里我们简单的介绍一下JSP平台以及它的一些重要的技术
JSP 是一种新的计算平台,它简化了在高度分布式 Internet 环境中的应用程序开发。JSP 旨在实现下列目标:
提供一个一致的面向对象的编程环境,而无论对象代码是在本地存储和执行,还是在本地执行但在 Internet 上分布,或者是在远程执行的。
提供一个将系统部署和版本控制冲突最小化的代码执行环境。
提供一个保证代码(包括由未知的或不完全受信任的第三方创建的代码)安全执行的代码执行环境。
提供一个可消除脚本环境或解释环境的性能问题的代码执行环境。
使开发人员的经验在面对类型大不相同的应用程序(如基于 Windows 的应用程序和基于 Web 的应用程序)时保持一致。
按照工业标准生成所有通信,以确保基于 JSP 的代码可与任何其他代码集成。
图3-3
JSP 具有两个主要组件:公共语言运行库和 JSP 类库。公共语言运行库是 JSP 的基础。您可以将运行库看作一个在执行时管理代码的代理,它提供核心服务(如内存管理、线程管理和远程处理),而且还强制实施严格的类型安全以及可确保安全性和可靠性的其他形式的代码准确性。事实上,代码管理的概念是运行库的基本原则。以运行库为目标的代码称为托管代码,而不以运行库为目标的代码称为非托管代码。JSP 的另一个主要组件是类库,它是一个综合性的面向对象的可重用类型集合,您可以使用它开发多种应用程序,这些应用程序包括传统的命令行或图形用户界面 (GUI) 应用程序,也包括基于 JSP 所提供的最新创新的应用程序(如 Web 窗体和 XML Web services)。
JSP还具有多编程语言,现在可提供Visual Basic J2EE、Visual C# J2EE、Visual C++ J2EE、Visual J# J2EE等。JSP为几种语言提供了统一的平台和统一的编程模型。
J2EE 是一组向 J2EE 程序员公开数据访问服务的类。J2EE 为创建分布式数据共享应用程序提供了一组丰富的组件。它提供了对关系数据、XML 和应用程序数据的访问,因此是 JSP 中不可缺少的一部分。J2EE 支持多种开发需求,包括创建由应用程序、工具、语言或 Internet 浏览器使用的前端数据库数据端和中间层业务对象。
可使用 JSP 开发下列类型的应用程序和服务:
控制台应用程序。
Windows GUI 应用程序(Windows 窗体)。
JSP 应用程序。
XML Web services。
Windows 服务。
我的办公信息管理系统管理信息系统中包括Windows窗体和JSP两种应用程序。

3.4 J2EE技术探讨

3.4.1 J2EE概述

J2EE 提供对 Microsoft SQL Server 等数据源以及通过 OLE DB 和 XML 公开的数据源的一致访问。数据共享使用者应用程序可以使用 J2EE 来连接到这些数据源,并检索、操作和更新数据。
J2EE 有效地从数据操作中将数据访问分解为多个可以单独使用或一前一后使用的不连续组件。J2EE 包含用于连接到数据库、执行命令和检索结果的 JSP 数据提供程序。您可以直接处理检索到的结果,或将其放入 J2EE DataSet 对象,以便与来自多个源的数据或在层之间进行远程处理的数据组合在一起,以特殊方式向用户公开。J2EE DataSet 对象也可以独立于 JSP 数据提供程序使用,以管理应用程序本地的数据。
3.4.2 J2EE访问数据的基本方法
J2EE 结构如下:
图3-4

从图3-4可以看出,J2EE提供了两种访问数据的基本方法:通过DataReader和DataSet。下面分别讨论这两种方法:

1)DataReader:
J2EE DataReader 从数据库中检索只读、只进的数据流。查询结果在查询执行时返回,在并存储在数据端的网络缓冲区中,直到您使用 DataReader 的 Read 方法对它们发出请求。使用 DataReader 可以提高应用程序的性能,因为一旦数据可用,DataReader 方法就立即检索该数据,而不是等待返回查询的全部结果;并且在默认情况下,该方法一次只在内存中存储一行,从而降低了系统开销。
DataReader 提供未缓冲的数据流,该数据流使过程逻辑可以有效地按顺序处理从数据源中返回的结果。由于数据不在内存中缓存,所以在检索大量数据时,DataReader 是一种适合的选择。
2)DataSet
J2EE DataSet 是数据的一种内存驻留表示形式,无论它包含的数据来自什么数据源,它都会提供一致的关系编程模型。一个 DataSet 表示整个数据集,其中包含对数据进行包含、排序和约束的表以及表间的关系。
如图3-4所示,一个DataSet可以包含多个DataTable,利用数据存储的信息对它们进行填充.可以在DataSet中包含DataRelation对象, DataRelation对象用来描述DataSet中表之间的关系。这个DataRelation对象的所包含的约束就是我们在3.14中所讲的数据库完整性设计的内容。
总之DataSet最大的特点就是:不依赖于连续的活动连接,其值是数据源的一个内存副本。
图3-5
图3-5描述了用DataSet操作SQLserver2000的一般方法。
用DataSet访问常规数据源的基本步骤是,先建立一个DataAdapter对象,如果只需只读访问数据,那么只要对DataAdapter指定一个SelectCommand即可。然后用DataAdapter填充DataSet。如果需要插入,更新或者删除数据,则需要在DataAdapter中相应的指定InsertCommand、UpdateCommand以及DeleteCommand,最后调用DataAdapter的Update方法。
3.4.3 使用J2EE操作SQLserver2000
我的办公信息管理系统管理信息系统使用的是SQLserver2000数据库。
在阐述了一些J2EE的基本内容后,我们来有针对性的讲一下如何通过J2EE访问SQLserver2000数据库。
最新的JSP1.1 包括 SQL Server JSP 数据提供程序(用于 Microsoft SQL Server 7.0 版或更高版本)、OLE DB JSP 数据提供程序和 ODBC JSP 数据提供程序以及Oracle JSP 数据提供程序。分别可以建立四种不同连接,其主要功能如下。
(1) SqlConnection - 该对象管理与 SQL Server 7.0 版或更高版本的连接。通过忽略 OLE DB 层(还包括其他措施),对该对象进行优化以便将其用于 SQL Server 7.0 或更高版本。
(2) OleDbConnection - 该对象管理与可通过 OLE DB 访问的任何数据存储区的连接。
(3) OdbcConnection – 该对象管理与通过使用连接字符串或 ODBC 数据源名称 (DSN) 创建的数据源的连接。
(4) OracleConnection – 该对象管理与 Oracle 数据库的连接。
虽说SQL Server JSP 数据提供程序、OLE DB JSP 数据提供程序和 ODBC JSP 数据提供程序都能访问SQLserver数据库,但微软公司推荐使用SQL Server JSP 数据提供程序
办公信息管理系统管理信息系统使用的就是SQL Server JSP 数据提供程序。以下通过一些例子介绍办公信息管理系统管理系统中是如何通过SQL Server JSP 数据提供程序与SQLserver2000数据库进行交互的。
在J2EE中使用SQL Server JSP 数据提供程序,首先要导入System.Data.SqlClient命名空间。我们举例说明J2EE与SQLserver2000数据库交互的两种常见方式:A.直接使用数据命令;B.使用数据集。
A. 使用数据命令与数据库交互
要在数据库中执行操作,应执行 SQL 语句或存储过程(它包括 SQL 语句)。您使用 SQL 语句或存储过程读写行并执行聚合函数,例如添加或求平均值。您还使用 SQL 语句或存储过程创建或修改表或列、执行事务等。
以下是一个办公信息管理系统管理系统中一个验证登陆的函数
Public Function validateLogin(ByVal uid As String, ByVal pwd As String) As Boolean
Dim IsCorrect As Boolean = False
Dim cnmy As New SqlConnection(“server=(local);database=lib2004;uid=sa;pwd=”)
Dim cmd As New SqlCommand
With cmd
.Connection = cnmy
.CommandType = CommandType.Text
.CommandText = "select count() from manager where Man_id=@Man_id and Man_pwd=@Man_pwd"
End With
Dim mMan_id As New SqlParameter(“@Man_id”, SqlDbType.NVarChar, 50)
Dim mMan_pwd As New SqlParameter(“@Man_pwd”, SqlDbType.NVarChar, 12)
With cmd.Parameters
.Add(mMan_id)
.Add(mMan_pwd)
End With
mMan_id.Value = uid
mMan_pwd.Value = pwd
Try
cnmy.Open()
If cmd.ExecuteScalar = 1 Then
IsCorrect = True
End If
Catch ex As Exception
MessageBox.Show(“登陆验证时数据库发生错误” + vbCrLf + ex.Message, _
“error”, MessageBoxButtons.OK, MessageBoxIcon.Stop)
Return False
Finally
cnmy.Close()
If Not cnmy Is Nothing Then
cnmy.Dispose()
End If
End Try
Return IsCorrect
End Function
现在对这个函数按步骤详细说明。
该例子体现了如何执行sql语句。
该实例用到了System.Data.SqlClient命名空间中两个重要的对象:1.连接对象SqlConnection;2.sql命令对象SqlCommand。
SqlConnection 对象表示与 SQL Server 数据源的一个唯一的会话。对于数据端/服务器数据库系统,它相当于到服务器的网络连接。
其重要属性如下表:
ConnectionString 获取或设置用于打开 SQL Server 数据库的字符串。
ConnectionString格式如下:
使用sql验证方式:(server=服务器名称;database=数据库名称;uid=用户名;pwd=密码)
使用windows集成验证(server=服务器名称;database=数据库名称;Integrated Security=SSPI)
SqlCommand对象表示要对 SQL Server 数据库执行的一个 T-SQL 语句或存储过程。其重要属性如下:
CommandText 获取或设置要对数据源执行的 Transact-SQL 语句或存储过程。
CommandTimeout 获取或设置在终止执行命令的尝试并生成错误之前的等待时间。
CommandType 获取或设置一个值,该值指示如何解释 CommandText 属性。
Connection 获取或设置 SqlCommand 的此实例使用的 SqlConnection。
SqlCommand 特别提供了以下对 SQL Server 数据库执行命令的方法:
ExecuteReader 执行返回行的命令。为了提高性能,ExecuteReader 使用 Transact-SQL sp_executesql 系统存储过程调用命令。因此,如果用于执行像 Transact-SQL SET 语句这样的命令,ExecuteReader 可能无法获得预期效果。
ExecuteNonQuery 执行 T-SQL INSERT、DELELE、UPDATE 及 SET 语句等命令。
ExecuteScalar 从数据库中检索单个值(例如一个聚合值)。
ExecuteXmlReader 将 CommandText 发送到 Connection生成一个 XmlReader 对象。
直接使用数据命令的基本步骤是:
(1)新建一个SqlConnection对象,设置其ConnectionString属性。
(2)新建一个SqlCommand对象,分别设置其CommandText、CommandTimeout、CommandType、Connection属性。
(3)如果要执行的T-SQL 语句或存储过程带有参数,则先要设定SqlCommand对象的Parameters属性。
(4)调用SqlConnection对象的open方法打开连接。
(5)执行SqlCommand命令。执行的方式及相应的返回结果见上表。
(6)调用SqlConnection对象的close方法关闭连接。
本例使用ExecuteScalar方法返回一个聚合函数count(
)的值,count()返回结果为所查询到记录的个数。如果用户名和密码均符合的话,则返回一条记录,此时Count()值为1,符合条件,就成功的通过了验证。
B.使用数据集
使用数据集DataSet与SQLserver数据库交互请参见3.3.2中关于DataSet的介绍。只是将通用的DataAdapter对象改为专用的SqlClient命名空间中的SqlDataAdapter对象即可,这里就不再重复。
4 系统使用说明
办公信息管理系统管理信息系统功能齐全,界面友好,高效的异常处理使程序不会突然中断。这里主要介绍系统的软硬件要求及安装方法。
4.1环境要求
方案 操作系统
数据服务器 Win2000 Server
Win2000 Advanced Server
Windows Server 2003 系列(推荐)
网页服务器 Win2000 Pro
Win2000 Server
Win2000 Advanced Server
WinXP Professional
Windows Server 2003 系列(推荐)
注意:在所有这些系统上,还要求安装有IIS。此外win2000系列至少要更新到sp2
数据端 Win9X系列版本
Win2K,XP,Win2003
4.2系统的安装
数据服务器的安装
1.安装SQLserver2000
2.在SQLserver2000的查询分析器中,执行我们提供的脚本lib2004.sql
3.建立一个用于专门操作“办公信息管理系统管理信息系统”数据库的帐号
网页服务器的安装
1.确认已经安装了IIS
2.安装JSP
3.安装MDAC 2.8
4.安装办公信息管理系统管理信息系统(WebForms)
5.然后在IIS对应的虚拟目录中设定sql连接字符串的值
数据端的安装
1.安装JSP
2.安装MDAC 2.8
3.安装办公信息管理系统管理信息系统(管理员版)
4.第一次运行程序时会提醒设置数据服务器
数据服务器连接信息以及登陆信息请咨询管理员
4.3常见操作
登陆验证、、、综合查询等常见的办公信息管理系统事务,在系统中都有体现。详细的使用方法请参考程序的帮助文档,这里不再重复。

5 程序源代码经典部分选录

<%@ page contentType="text/html; charset=gb2312" language="java"  %>
<%@ page import="java.util.*"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.text.*"%>
<%@ page import="cn.edu.buaa.nlsde.db.*"%>
<%request.setCharacterEncoding("GB2312");
String TheMessage = "";
String sql1 = "";
String sql2 = "";
String sql3 = "";
String sql4 = "";
String TheAddDate = "";
int QueryLabel = 0;
String TheName = "";
String TheDepartment = "";
String TheProjectName = "";
int TheFundTypeA = 0;
int TheFundTypeB = 0;
int TheFundTypeC = 0;
int TheFundTypeD = 0;
String TheSummary = "";
String TheRemark = "";
String TheModifyDate = "";
int TheSum = 0;
String temp = "";
String SqlString = "";
Calendar cal = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String Date = format.format(cal.getTime());
format = new SimpleDateFormat("yyyy");
String Year = format.format(cal.getTime());
format = new SimpleDateFormat("MM");
String Month = format.format(cal.getTime());
format = new SimpleDateFormat("dd");
String Day = format.format(cal.getTime());
ResultSet RSRecordResult = null;
ResultSet RSThisRecord = null;
Hashtable HTThisRecord = new Hashtable();
//判断用户是否登录
if (session.getAttribute("ID") == null) {
response.sendRedirect("../login.jsp");
}
//判断用户是否具有财务管理员身份
if (session.getAttribute("IsFinancialManager").equals("False")) {
response.sendRedirect("finance.jsp");
}
//连接系统数据库
//Connection conn = (new DBConnect()).getODBCConn("EIMS");
Connection conn = (new DBConnect()).getConnPoolConn("eims");
Statement stmt = conn.createStatement();
boolean Warning = false;
//查询某个财务记录
if (request.getParameter("Query") != null) {
//获得用户的查询条件
if (request.getParameter("QueryCheck1") != null
&& (request.getParameter("FinancialRecordID") != null)) {
sql1 = "and ID=" + request.getParameter("FinancialRecordID");
}
else {
sql1 = " ";
}
if (request.getParameter("QueryCheck2") != null
&& (request.getParameter("FinancialProjectName") != null)) {
sql2 =
" and ProjectName='"
+ request.getParameter("FinancialProjectName")
+ "'";
}
else {
sql2 = " ";
}
if (request.getParameter("QueryCheck3") != null) {
sql3 =
" and Name='" + request.getParameter("SelectName") + "'";
}
else {
sql3 = " ";
}
if (request.getParameter("QueryCheck4") != null) {
TheAddDate =
request.getParameter("AddYear")
+ "-"
+ request.getParameter("AddMonth")
+ "-"
+ request.getParameter("AddDay");
sql4 = " and AddDate='" + TheAddDate + "' ";
}
else {
sql4 = " ";
}
SqlString =
"select * from FinancialRecord where AccountName='"
+ session.getAttribute("Name")
+ "' "
+ sql1
+ sql2
+ sql3
+ sql4
+ " order by Name";
System.out.println(SqlString);
RSRecordResult = stmt.executeQuery(SqlString);
TheMessage = "您查询的财务记录如下";
QueryLabel = 2;
}
//用户选定了查询出来的某个财务记录
else if (request.getParameter("SelectRecord") != null) {
TheMessage = "请在下面修改此条财务记录";
RSThisRecord =
stmt.executeQuery(
"select * from FinancialRecord where ID="
+ request.getParameter("RadioFinancialRecord"));
QueryLabel = 3;
while (RSThisRecord.next()) {
HTThisRecord.put("ID", new Integer(RSThisRecord.getInt(1)));
HTThisRecord.put("Name", RSThisRecord.getString(2));
HTThisRecord.put("ProjectName", RSThisRecord.getString(4));
HTThisRecord.put(
"FundTypeA",
new Integer(RSThisRecord.getInt(5)));
HTThisRecord.put(
"FundTypeB",
new Integer(RSThisRecord.getInt(6)));
HTThisRecord.put(
"FundTypeC",
new Integer(RSThisRecord.getInt(7)));
HTThisRecord.put(
"FundTypeD",
new Integer(RSThisRecord.getInt(8)));
HTThisRecord.put("Summary", RSThisRecord.getString(10));
HTThisRecord.put("Remark", RSThisRecord.getString(11));
HTThisRecord.put(
"AddDate",
RSThisRecord.getString(13).substring(0, 10));
}
}
//用户对选定的财务记录进行了更新
else if (request.getParameter("UpdateRecord") != null) {
//校验用户的输入
try {
NumberFormat numberformat = NumberFormat.getInstance();
numberformat.parse(request.getParameter("UpdateFundTypeA"));
numberformat.parse(request.getParameter("UpdateFundTypeB"));
numberformat.parse(request.getParameter("UpdateFundTypeC"));
numberformat.parse(request.getParameter("UpdateFundTypeD"));
ResultSet RSLinkedDepartment =
stmt.executeQuery(
"select Department from PSLogins where Name='"
+ request.getParameter("UpdateName")
+ "'");
TheName = request.getParameter("UpdateName");
while (RSLinkedDepartment.next()) {
TheDepartment =
RSLinkedDepartment.getString("Department");
}
TheProjectName = request.getParameter("UpdateProjectName");
TheFundTypeA =
new Integer(request.getParameter("UpdateFundTypeA"))
.intValue();
TheFundTypeB =
new Integer(request.getParameter("UpdateFundTypeB"))
.intValue();
TheFundTypeC =
new Integer(request.getParameter("UpdateFundTypeC"))
.intValue();
TheFundTypeD =
new Integer(request.getParameter("UpdateFundTypeD"))
.intValue();
TheSummary = request.getParameter("UpdateSummary");
TheRemark = request.getParameter("UpdateRemark");
TheModifyDate = Date;
TheSum =
TheFundTypeA + TheFundTypeB + TheFundTypeC + TheFundTypeD;
//修改此条财务记录
stmt.executeUpdate(
"update FinancialRecord set Name='"
+ TheName
+ "',Department='"
+ TheDepartment
+ "',FundTypeA="
+ TheFundTypeA
+ ",FundTypeB="
+ TheFundTypeB
+ ",FundTypeC="
+ TheFundTypeC
+ ",FundTypeD="
+ TheFundTypeD
+ ",Sum="
+ TheSum
+ ",Summary='"
+ TheSummary
+ "',Remark='"
+ TheRemark
+ "',ModifyDate='"
+ TheModifyDate
+ "',ProjectName='"
+ TheProjectName
+ "' Where ID="
+ request.getParameter("UpdateID"));
QueryLabel = 3;
TheMessage = "记录已经修改成功";
}
catch (Exception ex) {
TheMessage = "记录中的款项字段中出现了非数字内容,无法修改此记录,请重填记录";
Warning = true;
QueryLabel = 3;
}
RSThisRecord =
stmt.executeQuery(
"select * from FinancialRecord where ID="
+ request.getParameter("UpdateID"));
while (RSThisRecord.next()) {
HTThisRecord.put("ID", new Integer(RSThisRecord.getInt(1)));
HTThisRecord.put("Name", RSThisRecord.getString(2));
HTThisRecord.put("ProjectName", RSThisRecord.getString(4));
HTThisRecord.put(
"FundTypeA",
new Integer(RSThisRecord.getInt(5)));
HTThisRecord.put(
"FundTypeB",
new Integer(RSThisRecord.getInt(6)));
HTThisRecord.put(
"FundTypeC",
new Integer(RSThisRecord.getInt(7)));
HTThisRecord.put(
"FundTypeD",
new Integer(RSThisRecord.getInt(8)));
HTThisRecord.put("Summary", RSThisRecord.getString(10));
HTThisRecord.put("Remark", RSThisRecord.getString(11));
HTThisRecord.put(
"AddDate",
RSThisRecord.getString(13).substring(0, 10));
}
}
else {
TheMessage = "请在下面填写您要修改的财务记录的查询条件";
QueryLabel = 1;
}
%>



<HTML>
<HEAD>
<TITLE>公司财务信息管理系统</TITLE>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</HEAD>

<BODY BGCOLOR="">

<table width=800 border=0 bgcolor=#164DA8 cellspacing=1 cellpadding=2
align=center>
<tr bgcolor=white>
<td valign=middle><img src="../image/jsplogo.jpg" width=796 height=100></td>
</tr>
</table>
<table width="800" border="0" bordercolor="#164DA8" align="center"
cellpadding="0" cellspacing="0">
<tr>
<td height="13"><img src=".././image/banner2.jpg" width="800"
height="12"></td>
</tr>
</table>
<table width=800 border=0 bgcolor=#164DA8 cellspacing=1 cellpadding=2
align=center>
<tr>
<td colspan=3>
<div align="center"><font color=white>
公司办公信息管理系统->公司财务信息管理系统->修改财务记录[当前用户- <%=session.getAttribute("Name")%>
] </font></div>
</td>
</tr>
<tr bgcolor=white>
<td><a href=".././html/home.jsp"><font color="#104DAD">返回系统主页</font></a></td>
<td align=center><%if (Warning == false) {%> <font color="#104DAD"><%=TheMessage%></FONT>
<%}
else {%> <font color=Red><%=TheMessage%></font> <%}%></td>
<td align=right><a href="finance.jsp"><font color="#104DAD">返回上一级网页</font></a></td>
</tr>
</table>
<table width="800" border="0" bordercolor="#164DA8" align="center"
cellpadding="0" cellspacing="0">
<tr>
<td height="13"><img src=".././image/banner2.jpg" width="800"
height="12"></td>
</tr>
</table>
<br>



<FORM ACTION="modifyfinancialrecord.jsp" METHOD=POST><%if (QueryLabel == 1) {%>
<TABLE CELLPADDING=1 CELLSPACING=2 BORDER=1 bordercolor="#164DA8"
WIDTH=800 align=center>
<TR VALIGN="middle" ALIGN="center">
<TD WIDTH=20% bgcolor=#B5C7EF><img src="../image/finance1.jpg"></td>
<td>

<table CELLPADDING=1 CELLSPACING=1 BORDER=1 align=center width=100%
bgcolor=White>
<tr height=35>
<td><input type=checkbox name=QueryCheck1 value="on"></td>
<td>财务记录ID</td>
<td><INPUT TYPE="text" NAME="FinancialRecordID" VALUE="" size=50></td>
</tr>
<tr height=35>
<td><input type=checkbox name=QueryCheck2 value="on"></td>
<td>财务项目名称</td>
<td><INPUT TYPE="text" NAME="FinancialProjectName" VALUE="" size=50>
</td>
</tr>
<tr height=35>
<td><input type=checkbox name=QueryCheck3 value="on"></td>
<td width=25><font color="#164DA8">财务记录经手人</font></td>
<td><SELECT NAME="SelectName">
<%ResultSet RSPersons =
stmt.executeQuery("select Name from PSLogins order by Name");
while (RSPersons.next()) {
temp = RSPersons.getString("Name");%>
<OPTION VALUE="<%=temp%>"><%=temp%></OPTION>
<%}%>
</SELECT></td>
</tr>
<tr height=35>
<td><input type=checkbox name=QueryCheck4 value="on"></td>
<td width=25><font color="#164DA8">财务记录添加日期</font></td>
<td><select name="AddYear" size=1>
<OPTION VALUE="<%=Year%>"><%=Year%></OPTION>
<%for (int YearCounter = 1990; YearCounter <= 2050; YearCounter++) {%>
<OPTION VALUE="<%=YearCounter%>"><%=YearCounter%></OPTION>
<%}%>
</select><select name="AddMonth" size=1>
<OPTION VALUE="<%=Month%>"><%=Month%></OPTION>
<%for (int MonthCounter = 1; MonthCounter <= 12; MonthCounter++) {%>
<OPTION VALUE="<%=MonthCounter%>"><%=MonthCounter%></OPTION>
<%}%>
</select><select name="AddDay" size=1>
<OPTION VALUE="<%=Day%>"><%=Day%></OPTION>
<%for (int DayCounter = 1; DayCounter <= 31; DayCounter++) {%>
<OPTION VALUE="<%=DayCounter%>"><%=DayCounter%></OPTION>
<%}%>
</select></td>
</tr>
</table>

<TABLE CELLPADDING=0 CELLSPACING=0 BORDER=1 WIDTH=100% align=center>
<TR VALIGN="top" ALIGN="center">
<TD WIDTH=100% align=center><INPUT TYPE="submit" NAME="Query"
VALUE="查询符合条件的财务记录"
style="border: 1px solid #3466BB; background-color: #B6CAEB; color: #3466BB">
</TD>
</TR>
<tr>
<td><div align="center">注意:您只能修改您作为会计经手人的财务记录!</div></td>
</tr>
</table>

</td>
</TR>
</table>
<br>
<%}%> <%if (QueryLabel == 2) {%>

<table width=800 border=0 bgcolor=#164DA8 cellspacing=1 cellpadding=2
align=center>

<tr>
<td><font color=white>选中</font></td>
<td><font color=white>记录ID</font></td>
<td><font color=white>记录经手人</font></td>
<td><font color=white>部门</font></td>
<td><font color=white>所属财务项目</font></td>
<td><font color=white>款项A</font></td>
<td><font color=white>款项B</font></td>
<td><font color=white>款项C</font></td>
<td><font color=white>款项D</font></td>
<td><font color=white>合计</font></td>
<td><font color=white>添加日期</font></td>
<td><font color=white>最新修改日期</font></td>
</tr>
<%int index = 0;
while (RSRecordResult.next()) {
index = RSRecordResult.getInt("ID");
out.println(
"<tr bgcolor=white><td><input type=radio name=RadioFinancialRecord value="
+ index
+ "></td>");
out.println("<td>" + index + "</td>");
out.println("<td>" + RSRecordResult.getString("Name") + "</td>");
out.println(
"<td>" + RSRecordResult.getString("Department") + "</td>");
out.println(
"<td>" + RSRecordResult.getString("ProjectName") + "</td>");
out.println(
"<td>" + RSRecordResult.getInt("FundTypeA") + "</td>");
out.println(
"<td>" + RSRecordResult.getInt("FundTypeB") + "</td>");
out.println(
"<td>" + RSRecordResult.getInt("FundTypeC") + "</td>");
out.println(
"<td>" + RSRecordResult.getInt("FundTypeD") + "</td>");
out.println("<td>" + RSRecordResult.getInt("Sum") + "</td>");
out.println(
"<td>"
+ RSRecordResult.getString("AddDate").substring(0, 10)
+ "</td>");
temp = RSRecordResult.getString("ModifyDate");
if (temp != null) {
temp = temp.substring(0, 10);
}
out.println("<td>" + temp + "</td></tr>");
}
%>
</table>

<table width="800" border="0" bordercolor="#164DA8" align="center"
cellpadding="0" cellspacing="0">
<tr>
<td height="13"><img src=".././image/banner2.jpg" width="800"
height="12"></td>
</tr>
</table>
<p align=center><input type=submit name=SelectRecord value=选中某条财务记录
style="border: 1px solid #3466BB; background-color: #FFFFFF; color: #3466BB">
<%}%> <%if (QueryLabel == 3) {%>
<TABLE CELLPADDING=1 CELLSPACING=2 BORDER=1 bordercolor="#164DA8"
WIDTH=800 align=center>
<TR VALIGN="middle" ALIGN="center">
<TD WIDTH=20% bgcolor=#B5C7EF><img src="../image/finance1.jpg"></td>
<td>

<table CELLPADDING=1 CELLSPACING=1 BORDER=1 align=center width=100%>
<tr>
<td width=30%>财务记录号</td>
<td><%=((Integer)HTThisRecord.get("ID")).intValue()%> <input
name=UpdateID type=hidden
value="<%=((Integer)HTThisRecord.get("ID")).intValue()%>"></td>
</tr>
<tr>
<td width=30%>财务记录添加日期</td>
<td><%=HTThisRecord.get("AddDate")%></td>
</tr>
<tr>
<td width=30%>经手人</td>
<td><Select name=UpdateName>
<option value="<%=HTThisRecord.get("Name")%>"><%=HTThisRecord.get("Name")%></option>
<%ResultSet RSPersons =
stmt.executeQuery("select Name from PSLogins order by Name");
while (RSPersons.next()) {
temp = RSPersons.getString("Name");
out.println("<option value=" + temp + ">" + temp + "</option>");
}%>
</select></td>
</tr>
<tr>
<td width=30%>所属财务项目</td>
<td><Select name=UpdateProjectName>
<option value="<%=HTThisRecord.get("ProjectName")%>"><%=HTThisRecord.get("ProjectName")%></option>
<%ResultSet RSFinancialProject =
stmt.executeQuery(
"select * from FinancialProject order by FinancialProjectName");
while (RSFinancialProject.next()) {
temp = RSFinancialProject.getString("FinancialProjectName");
out.println("<option value=" + temp + ">" + temp + "</option>");
}%>
</select></td>
</tr>
<tr>
<td width=30%>款项A</td>
<td><input name=UpdateFundTypeA
value="<%=((Integer)HTThisRecord.get("FundTypeA")).intValue()%>"></td>
</tr>
<tr>
<td width=30%>款项B</td>
<td><input name=UpdateFundTypeB
value="<%=((Integer)HTThisRecord.get("FundTypeB")).intValue()%>"></td>
</tr>
<tr>
<td width=30%>款项C</td>
<td><input name=UpdateFundTypeC
value="<%=((Integer)HTThisRecord.get("FundTypeC")).intValue()%>"></td>
</tr>
<tr>
<td width=30%>款项D</td>
<td><input name=UpdateFundTypeD
value="<%=((Integer)HTThisRecord.get("FundTypeD")).intValue()%>"></td>
</tr>
<tr>
<td width=30%>摘要</td>
<td><input name=UpdateSummary
value="<%=HTThisRecord.get("Summary")%>"></td>
</tr>
<tr>
<td width=30%>备注</td>
<td><input name=UpdateRemark value="<%=HTThisRecord.get("Remark")%>"></td>
</tr>
</table>
<p align=center><input type=submit name=UpdateRecord value=修改此条财务记录
style="border: 1px solid #3466BB; background-color: #FFFFFF; color: #3466BB">
<%}%>
</td>
</tr>
</table>
</FORM>
</BODY>
</HTML>
<%DBConnectionManager.getInstance().freeConnection("eims", conn);%>

毕业设计成果

开发了一套基于JSP平台的办公信息管理系统管理信息系统,系统可以正常投入使用,并且功能非常强大,性能十分良好。
此外在论文部分还讨论了大量的开发技术。

致谢

首先要感谢我的老师章美月,她在我毕业设计的过程中,给了我很大的帮助。在论文的研究内容上,她给我指明了方向;在研究方法上,她传授给我很多经验。章老师平易近人的风格以及严谨的学术作风给人留下了深刻的印象
其次要感谢我的老师刘文斌,他那渊博的学识令人非常敬佩。在毕业设计期间,他对我的指导和帮助也使我获益匪浅。

参 考 文 献

1.刘方鑫 数据库原理与技术 电子工业出版社,2002
2.Kevin Hoffman JSP高级编程 清华大学出版社,2002
3.Jason Bell 高级编程 清华大学出版社,2002
4.Tony Bain JSP 和SQLserver 2000高级编程 清华大学出版,2002
5.Evangelos Petroutsos Jsp 从入门到精通 电子工业出版社,2002
6.Microsoft SQL Server 2000数据开发手册 科学出版社,2001
7.Marty Hall Web 编程指南 清华大学出版社,1999
8.Scott Worley JSP 技术内幕 人民邮电出版社,2002
9.A.Russell Jones JSP从入门到精通 电子工业出版社,2003
10.Steve Stein How Jsp Generates SQL Statements for Concurrency Control MSDN for Jsp 2003,2002

结论

引言
任何可能同时被多个用户访问或修改数据的应用程序,都需要进行并发控制。否则,一个用户更改记录时可能不经意的覆盖了其他用户的更改。Jsp的设计工具可以生成“保持所有值”方式的开放式并发SQL语句或生成“最后的更新生效”方式的SQL语句来更新数据。这篇文章将解释:
不同的SQL语句是如何生成的
如何修改自动生成的SQL语句可以提高执行效率
阅读此文章时应具备的一些知识
你需要具备以下知识:
基本的J2EE概念,包括数据集(DataSet)以及数据适配器(DataAdapters)。更多信息请参见J2EE 数据访问介绍(Introduction to Data Access with J2EE)。
数据并发机制以及会操作Jsp。更多内容请参见 介绍 J2EE 中的数据并发(Introduction to Data Concurrency in J2EE)。
自动生成的SQL语句在哪里
自动生成的SQL语句在command对象的CommandText属性里。在设计阶段配置DataAdapter对象时或使用CommandBuilder对象时SQL命令被自动生成。更多信息,请参见 并发与CommandBuilder对象(Concurrency and Command Builder Objects)。
配置DataAdapter对象
从工具箱的数据选项卡中拖一个DataAdapter对象
从服务器资源管理器拖一个数据表
选中已有的DataAdapter对象,然后单击在属性窗口底部的“配置数据适配器”链接
CommandBuilder对象
CommandBuilder对象在运行时刻被创建,更多信息请参阅 SqlCommandBuilder 或 OleDbCommandBuilder。
并发控制与数据适配器(DataAdapter)
使用“数据适配器配置向导”配置数据适配器时,你可以选择是否使用开放式并发来生成Update和Delete语句。
一些思考和注意事项
你的数据源必须有一个主键才能以开放式并发方式生成SQL语句
当使用从“服务器资源管理器”拖放一个数据表的方式来创建DataAdapter对象时,DataAdapter对象自动生成基于开放式并发的Update和Delete语句。如果你不想使用开放式并发,右击DataAdapter对象,从快捷菜单中选择“配置数据适配器”,然后在“高级SQL生成选项”对话框中清除“使用开放式并发”选项的选定。向导则会重新创建不带并发检测的SQL语句。
当重新配置现有的DataAdapter时,应注意“高级SQL生成选项”对话框里的选项已经全部恢复默认。例如最初配置DataAdapter时没有选定“使用开放式并发”选项,但是当重新配置DataAdapter时,“使用开放式并发”选项却会被选定,即便你根本没有打开过“高级SQL生成选项”对话框。
如果你在“数据适配器配置向导”的“选择查询类型”页面选择“使用现有的存储过程”,则“使用开放式并发”选项将不可用。存储过程仍按其原来的方式执行。如果想使用并发检测的话,必须将其包括到存储过程中、或在你的应用程序中编写相应的代码。
当使用开放式并发来创建SQL命令时,不会对二进制数据列验证进行并发处理。这将导致用这种方法对大的二进制记录集执行按位比较算法时的效率低下。
用向导生成SQL语句
为了理解Jsp如何使用开放式并发来生成SQL语句,让我们来看看用“数据适配器配置向导”生成的Update语句。我们将查看同一条语句在选择“使用开放式并发”选项和不选择“使用开放式并发”选项时的不同状态。
你会注意到,选择开放式并发与不选择开放式并发所生成SQL语句的区别只存在于Where子句上。
注:以下的例子使用用“数据适配器配置向导”生成的Update语句,并从NorthWind示例数据库的Customers表中选择了若干列。
使用开放式并发的Update语句
这个例子使用了“数据适配器配置向导”的默认配置,即选中了“使用开放式并发”选项。
注: 当使用开放式并发时,生成的command的参数集里还存在一个参数副本。第二个参数集(带@Original_前缀的那个)保存了最初从数据源里读取的值。
检查Where子句发现,每一个生成的语句都要检测数据库当前的值是否等于最初读取的值(例,WHERE City = @Original_City)。通过数据库中的每个字段与最初读取的值相比较,我们很容易确定是否同时有其他用户修改了某个字段。如果Where子句不成立,就没有记录会被修改,与此同时还引发了一个“数据库并发”异常。如果数据源的某个字段为空值(NULL),生成的SQL语句同样验证最初读取的记录是否也为空值。
UPDATE Customers
SET CustomerID = @CustomerID, CompanyName = @CompanyName, ContactName
= @ContactName, ContactTitle = @ContactTitle, City = @City
WHERE (CustomerID = @Original_CustomerID) AND (City = @Original_City
OR @Original_City IS NULL AND City IS NULL) AND (CompanyName =
@Original_CompanyName) AND (ContactName = @Original_ContactName OR
@Original_ContactName IS NULL AND ContactName IS NULL) AND (ContactTitle =
@Original_ContactTitle OR @Original_ContactTitle IS NULL AND
ContactTitle IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, City
FROM Customers WHERE (CustomerID = @CustomerID)
不使用开放式并发的Update语句
这个例子更改了“数据适配器配置向导”的高级选项,没有选中“使用开放式并发”选项。
以下的语句表明:只要数据库中一条记录满足CustomerID = @Original_CustomerID ,则所有的字段都会被更新。不管这条记录现在是什么样的值,它都将被设置为通过SQL语句传递到数据源的值。在这里没有任何关于并发的检测,也无法得知是否同时有其它用户在更改这条记录。 这种方式称为“最后的更新生效”方式。无论以前对这条记录进行过什么样的修改,更新操作都会执行。
UPDATE Customers
SET CustomerID = @CustomerID, CompanyName = @CompanyName,
ContactName = @ContactName, ContactTitle = @ContactTitle, City = @City
WHERE (CustomerID = @Original_CustomerID);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, City
FROM Customers WHERE (CustomerID = @CustomerID)
优化生成的SQL语句
Jsp生成“保持所有值”方式的SQL语句来实现开放式并发。虽然这可能没有生成最高效的SQL语句,但是它的却生成了可以对数据源所有列(包括主键)进行并发检测的SQL语句。
使用“保持所有值”方式实现开放式并发,当执行效率非常低下时,你可以手工修改生成的SQL语句以使它们不检查数据源的所有列。最常见的方式是使用时间戳或版本号字段。如果你的数据源包含一个每次修改记录时都会更新的时间戳字段,你只需要验证数据源中的时间戳和你程序中的时间戳二者是否匹配,就可以知道是否同时有其他用户修改了记录。
下面这条SQL语句使用检查时间戳模式。
注: 这个例子假设数据库已经设置了时间戳字段
UPDATE Customers SET CustomerID = @CustomerID, CompanyName = @CompanyName,
ContactName = @ContactName, ContactTitle = @ContactTitle, City = @City
WHERE (CustomerID = @Original_CustomerID) AND
(TimeStamp = @Original_TimeStamp);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, City,
TimeStamp FROM Customers WHERE (CustomerID = @CustomerID)
并发与CommandBuilder对象
当应用程序使用SqlCommandBuilder或者OleDbCommandBuilder时,生成的Update和Delete语句的CommandText属性被自动的以开放式并发方式创建。如果你不想用开放式并发,则可以通过修改DataAdapter对象的Update和Delete命令的CommandText属性来实现。更多内容,请参见OleDbCommand.CommandText属性 或 SqlCommand.CommandText属性。
结论
当使用开放式并发的“保存所有值”方法时,SQL语句在设计时由Jsp的设计工具自动生成或在运行时由CommandBuilde自动生成。它把数据库所有字段(包括主键)当前值与初始值进行比较,这可能不是一种最高效的方式。如果你的数据使用版本号或者时间戳方式控制并发,则可以通过修改生成的SQL语句来获取更高效的执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学长代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值