医药销售管理系统
1 系统分析.................................................................................................................................3
开发背景.......................................................................................................................3
需求分析.......................................................................................................................3
2 系统设计.................................................................................................................................3
系统目标.......................................................................................................................3
系统功能结构...............................................................................................................4
系统流程图...................................................................................................................4
3 软件架构.................................................................................................................................6
逻辑分层结构设计.......................................................................................................6
系统文件夹组织结构...................................................................................................7
实体对象设计...............................................................................................................7
定义 ActionForm..........................................................................................................8
持久层结构设计...........................................................................................................8
业务层结构设计.........................................................................................................10
页面结构设计.............................................................................................................11
4 配置文件...............................................................................................................................11
配置 ..............................................................................................................11
配置 ................................................................................................12
配置 ...............................................................................................12
5 实体及映射...........................................................................................................................12
药品实体映射.............................................................................................................12
药品类别实体映射.....................................................................................................13
销售明细实体映射.....................................................................................................13
用户实体映射.............................................................................................................14
6 公共类设计...........................................................................................................................14
Hibernate 过滤器.........................................................................................................14
SupperDao 类...............................................................................................................16
BaseAction 类 ..............................................................................................................17
DeleteAction 类 ...........................................................................................................18
字符串工具类.............................................................................................................18
7 国际化...................................................................................................................................18
国际化资源文件.........................................................................................................18
国际化实现.................................................................................................................19
8 系统登陆模块.......................................................................................................................19
查询用户.....................................................................................................................19
登陆请求.....................................................................................................................19
登录页面.....................................................................................................................19
9 药品类别信息管理...............................................................................................................20
药品类别持久层设计.................................................................................................20
药品类别的添加.........................................................................................................21
类别添加、修改请求处理...............................................................................21
类别添加页面...................................................................................................21
分页查看类别信息.....................................................................................................21
查询与删除请求处理.......................................................................................22
类别信息列表页面...........................................................................................22
类别的修改与删除.....................................................................................................22
药品类别统计.............................................................................................................22
JFreeChat 工具类 ..............................................................................................23
Action 请求........................................................................................................23
显示报表...........................................................................................................23
10 药品信息管理.....................................................................................................................23
药品对象持久层设计...............................................................................................24
药品信息的添加与修改...........................................................................................24
药品添加的请求处理.....................................................................................24
药品添加页面.................................................................................................25
分页查看所有药品...................................................................................................25
查看药品详细信息...................................................................................................25
模糊查询药品...........................................................................................................26
药品模糊查询请求处理.................................................................................26
药品模糊查询页面.........................................................................................26
高级查询...................................................................................................................27
查看库存...................................................................................................................27
药品批量删除...........................................................................................................27
批量删除请求处理.........................................................................................28
映射 JSP 页面中的按钮.................................................................................28
11 购买药品.............................................................................................................................28
选购药品...................................................................................................................28
结账...........................................................................................................................29
12 销售管理.............................................................................................................................29
明细信息查询...........................................................................................................29
销售排行统计...........................................................................................................30
13 进货/需求管理 ...................................................................................................................30
14 系统管理.............................................................................................................................31
添加管理员...............................................................................................................31
修改密码...................................................................................................................32
系统初始化...............................................................................................................32
15 运行项目.............................................................................................................................32
1 系统分析
随着计计算机技术的不断发展,应用软件迅速普及,大到厂矿校企,小到图书、餐
饮、医药管理等,随处都可看到它的身影。在以往依靠人工为主的医药销售管理方面,
计算机和计算机系统逐步唱起了主角,凭借省时、省力、低误差等优点,从根本上改变
了医药管理的传统模式,节省了物理资源,提高了工作效率。
开发背景
XX 医药抄手坐落于 XX 小区内,多年来本着经济、实惠、高质量服务的宗旨,赢
得了小区百姓的信赖,药品供应量非常大。面对庞大的信息量,经常出现统计失误、药
量供应不足的情况,医药超市经理决定使用一套合理、有效、使用的管理系统,对医药
超市进行统一的管理。
笔者受医药超市经理委托,开发一个医药销售管理系统,其宗旨是实现医药超市管
理的系统化、规范化、实用化,对药品进行统一管理。
需求分析
在日常医药管理中,面对众多的药品和众多不同需求的顾客,每天都会产生大量的
数据信息。以传统的手工方式来处理这些信息,操作比较繁琐,且效率低下。此时,一
套合理、有效、实用的医药销售管理系统就显得十分必要。利用其提供的药品查询、统
计功能,可以进行高效的管理,更好地为顾客服务。笔者通过对医药超市的实地考察,
从经营者和消费者的角度出发,以高效管理、快速满足消费者为原则,要求本系统具有
以下特点。
★ 具有良好的系统性能、友好的用户界面。
★ 较高的处理效率,便于用户使用。
★ 采用成熟的技术开发,全系统具有较高的技术水平和较长的生命周期。
★ 对销售信息进行统计排行
★ 尽可能地简化药品管理员的重复工作,提高工作效率。
2 系统设计
系统目标
根据医药超市的管理要求,指定医药销售管理系统目标如下。
★ 灵活的人机交互界面,操作简单方便、界面简洁美观。
★ 系统提供中、英文语言,实现国际化
★ 药品分类管理,并提供类别统计功能。
★ 实现各种查询,如多条件查询、模糊查询等。
★ 提供创建管理员账户及修改口令功能。
★ 可对系统销售信息进行统计分析。
★ 系统运行稳定、安全可靠。
系统功能结构
医药销售管理系统提供了四大功能,分别为“基本信息管理”、“进货/需求管理”、“药
品管理”、“系统管理”,具体结构如图 所示
图 医药销售管理系统功能结构图
系统流程图
医药销售管理系统流程如图 所示。
医药销售管理系统
基本信息管理 进货/需求管理 药品销售管理 系统管理
药
品
信
息
管
理
药
品
类
别
管
理
库
存
信
息
查
看
药
品
需
求
管
理
药
品
进
货
管
理
销
售
明
细
管
理
销
售
排
行
统
计
销
售
时
间
统
计
系
统
初
始
化
管
理
员
帐
号
管
理
图 医药销售管理系统流程图
医药销售管理系统
管理
员
进货/需求管理
基本信息管理
药品销售管理
系统管理
药品信息管理
删除药品
药品类别管理
查询药品
修改药品
添加药品
修改类别
查询类别
删除类别
添加类别
修改需求
查询需求
删除需求
添加需求
销售排行统计
查询销售明细
当日销售明细
库存修改
系统初始化
查询管理员
密码修改
添加管理员
类别统计
管理员登录
3 软件架构
在开发项目前,首先要对软件的结构进行设计,也称之为软件架构。此过程是对软
件整体结构的设计,如软件的逻辑分层结构、结构的实现、数据库等,特别是在 Java 的
大型项目中,还需要设计出程序中的包结构及接口等,非常复杂,需要程序员进行全面
的考虑。对于医药销售管理系统的整体涉及如下:
逻辑分层结构设计
医药销售管理系统由 4 层结构组成,并遵循 MVC 结构进行设计。4 层结构分别为
表示层、业务逻辑层、持久层与数据库层,如图 所示。
图 逻辑分层
其中,表示层与业务逻辑层均由 Struts 框架组成,表示层用于提供程序与用户交互
的界面,项目中主要通过 JSP、ActionForm 及 Struts 标签库进行展现;业务逻辑层用于
处理程序中的各种业务逻辑,项目中通过 Struts 框架的中央控制器及 Action 对象对业务
请求进行处理;持久层由 Hibernate 框架组成,负责应用程序与关系型数据库之间的操
作;数据库层为应用程序所使用的数据库,本实例中为 MySQL 数据库。对于 4 层结构
的具体实现如图 所示。
图 逻辑分层实现
医药销售管理系统
表示层
(Struts 框架)
业务逻辑层
(Struts 框架)
持久层
(Hibernate 框架)
数据库层
(MySQL 数据库)
医药销售管理系统
视图
JSP、
ActionForm、
Struts 标签
控制器
Action、
持久化
Hibernate API、
MySQL 数据
系统文件夹组织结构
规范系统的整体架构是一个项目开发的标准,特别是在团队开发项目中,在编写代
码之前,必须定制好项目的系统文件夹组织结构,以使程序条理清晰,利于后期的项目
整合。在 Java 项目中可以将不同作用、功能相类似的文件放置于同一个包中,这样既可
以保证团队开发的一致性,又可以将系统的整体结构规范化。创建完系统中可能用到的
文件夹或 Java 包之后,在开发时只需将所创建的类文件或资源文件保存到相应的文件夹
即可。医药销售管理系统的文件夹组织结构如图 所示。
图 医药销售管理系统的文件夹组织结构
实体对象设计
在应用 Hibernate 框架的项目中,实体对象的确立是其中的关键。实体对象与数据
库中的数据表相对应,并通过 O/R 映射建立实体与数据库的联系,Hibernate 完全通过
操作实体来操作数据库,所以首先要确定项目中的实体对象。在医药销售管理系统中,
实体对象及关系如图 所示。
图 医药销售管理系统中的实体对象及其关系
从图 中可以看到,药品实体对象为 Medicine 类,药品类别实体对象为 Category
类,销售明细实体为 SellDetail 类,操作用户实体为 User 类,这 4 个实体对象为医药销
售管理系统的核心实体对象,它们所对应的映射文件均为“类名+”文件。其中,
药品信息与药品类别为多对一关联关系,一个类别中包含多个药品对象;药品信息与销
售明细为一对多关联关系,多个销售明细对应一个药品对象;销售明细与用户之间为多
对多的关联关系,多个销售明细信息对应多个操作用户。
定义 ActionForm
ActionForm 是简单的 JavaBean,主要用来保存用户所输入的表单数据,Action 要获
取这些数据需要通过 ActionForm 对象进行传递。ActionForm 对表单的数据进行了封装,
在 JSP 页面与 Action 对象中提供了交互访问的方法。在使用过程中,可通过继承
对象来创建需要的 ActionForm 对象,项目中所涉及到
的 ActionForm 对象如图 所示。
图 项目中所涉及到的 ActionForm 对象
持久层结构设计
持久层结构通过 Hibernate 框架进行设计。由于 Hibernate 对不同对象的增、删、改、
查等操作具有一定的共性,如添加数据使用 save()方法、删除数据使用 delete()方法等,
项目中将这些具有共性的操作抽取出来,封装成一个类,其他数据库操作对象可继承此
类来拥有这些方法,从而减少程序中的多余代码,如图 所示。
图 持久层结构
SupperDao 类为所有数据库操作对象的父类,在此类中定义了对数据库进行操作的
常用方法,具体方法及说明如表 所示。
表 SupperDao 方法及说明
方法 说明
save() 用于保存一个对象
saveOrUpdate() 用于保存或更新一个对象
delete(Object obj) 用于删除一个对象,入口参数为 Object 类型
findByHQL() 通过 HQL 语句查询数据,入口参数为 String 类型的 HQL 语句
deleteByHQL() 通过 HQL 语句删除数据,入口参数为 String 类型的 HQL 语句
uniqueResult() 单值检索数据,入口参数 hql 为 HQL 查询语句、where 为查询条件
findPaging() 分页查询数据,入口参数 hql 为 HQL 查询语句、offset 为结果集的起
始位置、length 为返回结果集的条目数、where 为查询条件
这些方法均为数据库操作的常用方法,所以将其封装在单独的一个类中,对于各个
对象的数据库相关操作,可通过继承此类来获取这些常用方法。其子类对象有
CategoryDao 类、MedicineDao 类、SellDao 类、UserDao 类,其功能分别介绍如下。
CategoryDao 类:药品类别数据库操作对象,用于封装与药品类别相关的数据库操
作方法。
MedicineDao 类:药品信息数据库操作对象,用于封装与药品信息相关的数据库操
作方法。
SellDao 类:药品销售数据库操作对象,用于封装与药品销售相关的数据库操作方
法。
UserDao 类:用户数据库操作对象,用于封装与管理员及系统相关的数据库操作方
法。
业务层结构设计
业务层结构主要通过 Struts 框架进行设计,由 Struts 的中央控制器对各种操作请求
进行控制,并通过相应的 Action 对其进行业务处理,项目中所用到的 Action 对象及关
系如图 所示。
图 Action 对象及关系
Action、DispatchAction 与 LookUpDispatchAction 为 Struts 封装的 Action 对象,具
有不同的特点及作用,项目中通过继承这几个对象实现对不同业务请求的处理。除这 3
个对象外,图 中其余的 Action 对象均为自定义的 Action 对象。
在这些自定义的 Action 对象中,LanguageAction 与 LoginAction 用于处理国际化语
言及用户登录操作。由于二者不涉及过多的业务逻辑,它们都直接继承于 Action 对象。
BaseAction 对 象 与 DeleteAction 对 象 为 重 要 的 Action 对 象 , 二 者 都 继 承 了
DispatchAction 对象。项目中封装这两个对象的目的在于简化程序中的业务逻辑、提高
程序的安全性。在这两个对象中均对用户登录身份做出了严格的验证,其子类对象通过
继承不必再考虑用户登录的安全问题,而更专注于业务逻辑,同时通过继承还可以减少
程序的代码量。其中 BaseAction 对象的子类及作用如表 所示。
表 BaseAction 对象的子类及其作用
子类 作用
SellAction 封装药品销售的相关操作,处理封装药品销售请求
SystemAction 封装系统相关操作,处理系统级的请求
CategoryAction 封装药品类别相关操作,处理药品类别相关操作
MedicineAction 封装药品信息相关操作,处理封装药品信息的相关请求
RequireAction 封装药品需求及库存相关操作,处理药品需求相关请求
DeleteAction 对 象 继 承 了 LookUpDispatchAction 对 象 , 此 类 通 过 重 写
getKeyMethodMap()方法对数据进行批量删除操作,其子类对象及其作用如表 所示。
表 DeleteAction 对象的子类及其作用
子类 作用
DeleteMedicineAction 封装药品信息删除操作,用于批量删除药品信息
DeleteReqMedAction 封装药品需求信息删除操作,用于批量删除药品需求信息
页面结构设计
医药销售管理系统的页面结构采用框架进行设计,通过 HTML 语言中的<frameset>
标签及<frame>标签将页面分成 3 个部分,分别为页面头部、页面导航及内容页面,如
图 所示。
图 页面布局
此种布局方式将每一个页面单独置于一个框架之中,其中“页面头部”和“页面导航”
在登录之后是固定不变的,对于用户的操作将在“内容页面”显示结果。使用这种方式的
有点在于:
(1)避免了 JSP 页面中大量引用<include>动作标签。
(2)避免浏览器反复加载“页面头部”及“页面导航”等同样的内容,加快浏览器速度。
4 配置文件
在编写代码之前,需要做一些准备工作,如项目环境的搭建、项目所涉及到的第三
方类库的支持、 的配置等。在医药销售管理系统中,主要涉及到 Struts 框架、
Hibernate 框架及 JFreeChart 组件的应用,因此在项目开发之前,需要添加其类库支持。
配置
文件是 Web 项目的配置文件,在医药销售管理系统中,此文件需要配置
Struts 框架、JFreeChart 组件和过滤器等信息。
配置
Struts 框架实现了 MVC 模式, 和 文件是其两个重要的配
置文件,其中 文件实现了 Struts 的初始化加载,而 是它的核心
配置文件。 所做的工作比较多,包括 ActionForm 对象的定义、用户请
求和 Action 之间的映射、异常处理等重要的配置。
其 中 <form-beans> 标 签 用 于 注 册 实 例 中 所 涉 及 到 的 ActionForm 对 象 ,
<global-forwards>标签用于设置全局跳转,<action-mappings>标签配置用户请求 Action
对象的映射。
配置
文件是 Hibernate 的配置文件,在项目中,此文件配置了数据库的
方言、数据库链接信息、自动建表属性和打印 SQL 语句等属性。
5 实体及映射
Hibernate 是一个 ORM 产品,它完全可以操作对象的方式进行数据库操作,其实体
对象与数据表之间通过映射文件建立映射关系。因此,在医药销售管理系统中需要建立
实体对象与数据表之间的映射。
药品实体映射
药品实体对象的持久化类为 Medicine 类,此类封装了药品相关属性提供相应的
getXX()和 setXXX()方法。
药品对象与药品类别对象为多对一关联关系,所以在 Medicine 类中加入了药品类别
属性 category,其关联关系通过映射文件 进行映射。
映射文件 将实体对象 Medicine 映射为 tb_medicine 表,主键的生
成策略采用自动生成方式。此映射文件中,对于数据表的部分字段还通过 not-null、length、
unique 等属性映射字段的属性,其中 not-null 用于映射字段的非空属性、length 用于映
射字段的长度、unique 用于映射字段是否唯一。映射后的数据表如图 所示。
图 tb_medicine 表
药品类别实体映射
药品类别实体用于封装药品类别属性信息,其持久化类为 Category 类,与药品对象
存在一对多关联关系。
药品对象与药品类别对象为多对一关联关系,但从药品类别一端来看,药品类别对
象与药品对象又是一对多的关系,所以程序中采用了多对一双向关联进行映射。药品类
别实体对象的映射文件为 。
Category 类所映射的数据表为 tb_category,其中<ser>标签用于映射药品类别实体与
药品实体间的一对多关联关系,此种映射方式将在药品数据表中添加 categoryId 字段。
映射后的数据表 tb_category 如图 所示。
图 tb_categoy 表
销售明细实体映射
销售明细用于描述药品销售时的具体情况,如销售时间、销售人员、销售数量等。
这些信息十分重要,需要记录到数据库中,实例中将其封装为 SellDetail 类。
为了方便查看销售明细的总额信息,在 SellDetail 类中加入了 sellTotal()属性,此属
性并不进行数据表的映射,它只有一个与之对应的 get()方法,在此方法中通过单价与数
量的运算对 sellTotal 进行赋值,并将其返回。
销售明细实体的映射文件为 ,此映射文件中映射了两个多对一关
联关系,分别为与药品对象的多对一关系及操作用户间的多对一关系。
销售明细实体映射的数据表为 tb_selldetail。在映射文件 中,通
过两个<many-to-one>标签分别映射与药品对象及操作用户的多对一关联关系,并配置了
级联操作类型为 save-update。映射后的数据表结构如图 所示。
图 tb_selldetail 表
用户实体映射
在医药销售管理系统中,用户实体用于封装管理员的基本信息,如登录的用户名、
密码等属性,其类名为 User。
User 类中属性相对较少,其映射过程也相对简单。其映射文件为 。
用户实体所映射的数据表为 tb_user,其结构如图 所示。
图 tb_user 表
6 公共类设计
在 Java 程序开发中,如果一个功能反复被调用,则可将该功能抽取出来封装为一个
类作为公共类,在需要此功能的地方通过此类进行实现。公共类实质是代码的重用的一
种方式,在面向对象的开发模式中经常使用它来简化程序中的代码,提高程序的可读性。
下面是医药销售管理系统找那个的公共类设计。
Hibernate 过滤器
在没有使用 Spring 管理 Hibernate 的情况下,对 Hibernate 的管理仍然存在一定的难
度,特别是在 J2EE 开发中,线程安全、SessionFactory 对象、Session 对象、Hibernate
缓存及延迟加载等是程序设计中的难题,管理不当将会对程序造成极为严重的影响。在
医药销售管理系统中,将 SessionFactory 对象、Session 对象置于过滤器中,由过滤器对
其进行管理,从而解决了这些问题。
在 Web 项目中,以普通方式使用 Hibernate 将无法解决 Hibernate 延迟加载,如图
所示。当有一个业务请求查询数据时,首先要开启 Session 对象,然后 Hibernate 对
数据进行查询。在关闭 Session 对象,最后通过 JSP 页面来显示数据。在这一过程中,
如果查询数据时使用了延迟加载,当 JSP 页面显示数据信息时,Hibernate 将抛出异常信
息,因为此时 Session 对象已经关闭,Hibernate 不能再对数据进行操作。
图 普通方式
通过过滤器管理 Hibernate 的 Session 对象则可以避免此问题,其实现过程如图
所示。
图 Hibernate 过滤器
在 Web 容器启动时,过滤器被初始化,它将执行 init()方法,在后续的操作中不会
再次被执行;而当容器关闭时,过滤器将执行 destroy()方法。这两个方法恰好符合
SessionFactory 对象的生命周期,在运行期间只执行一次操作,可用于实例化及销毁
SessionFactory 对象。对于 Session 对象的关闭操作,可以在业务逻辑处理结束后、
response 请求转发大 View 层之前进行。实例将其封装在 HibernateFilter 类中,此类继承
了 Filter 类,它是一个过滤器。
开启 Session 查询数据(Lazy)
关闭 SessionJSP 页面
业务请求
业务请求
Init()方法
初始化 SessionFactory
doFilter()
过滤处理
业务处理
destroy()方法
销毁 SessionFactory
JSP 页面
SessinFactory
关闭 Session
Response
Response
Request
Request
为了保证线程的安全性,实例中将 Session 对象存放与 ThreadLocal 对象中,当用到
一个 Session 对象时,首先从 ThreadLocal 中获取,在无法获取的情况下才会开启一个新
的 Session 对象。同时,为了保证 Session 对象能在 resopnse 请求转发到 View 层之前被
关闭,实例采取了 try…finally 语句对 Session 对象进行关闭。
SupperDao 类
SupperDao 类为项目中所有数据库操作类的父类,此类封装了数据库操作的常用方
法。在此类中,由于 Hibernate 对数据的操作都需要用到 Session 接口,类中定义了一个
protected 类型的 Session 对象,为其子类提供了方便。
save()方法及 savaOrUpdate()方法都用于保存一个对象,其入口参数均为 Object 类型。
其中 saveOrUpdate()方法比 save()方法更智能一些,可以根据实体对象中的标识值来判
断保存还是更新操作。SupperDao 类中使用这两个方法对实体对象进行保存及更新操作。
删除操作的方法为 delete(),入口参数为 Object 类型,此方法通过 Session 接口的
delete()方法进行实现。
SupperDao 类为项目中所有数据库操作类的父类,在设计时应当考虑全面。Hibernate
的 HQL 查询语言提供了更为灵活的查询方式,在这个超类之中应该加入 HQL 的操作方
法,其中 findByHQL()方法用于根据指定的 HQL 查询语句查询结果集,deleteByHQL()
方法用于根据指定的 HQL 查询语句进行删除操作。
Hibernate 单值检索在查询后返回单个对象,当返回的结果包含多条数据时,
Hibernate 将抛出异常。此种操作可用于查询单条数据,如聚合函数 count()等。在
SupperDao 类中,单值检索的方法为 uniqueResult()。
此方法的入口参数为 HQL 查询语句及查询条件,其中查询条件为 Object[]数组类型,
用于装载查询语句中的参数。例如 HQL 语句“from Medicine m where =?”,此时即可
通过参数 where 对其进行动态赋值。
分页查询在程序开发中经常用到,不但方便查看,还可以减少结果集的返回数量,
提高数据访问效率。使用 Hibernate 的分页查询方法极为简单,只需要传入几个参数即
可,但在 SupperDao 类中对其进行了扩展,加入了 HQL 语句的动态赋值,其方法名为
findPaging()。
此方法入口参数有 4 个,其中参数 hql 为 HQL 查询语句,它允许传入参数中带有
占位符“?”的 HQL 语句;参数 offset 为查询结果集对象的起始位置;参数 length 为查询
结果的偏移量,也是返回数据的条目数;参数 where 为查询条件,属于 Object[]数组类
型,用于装载 HQL 语句中的参数。通过上述这几个参数基本可以满足项目中所有的分
页查询,当然遇到特殊情况时,可以通过子类对象重写此方法。
BaseAction 类
BaseAction 类是业务层,有一个超类对象,它继承了 Struts 的 DispatchAction 类,
同时还为子类对象提供公用方法。此类首先定义了 3 个 protected 类型的变量,分别用于
设置每页的记录数、本地语言信息及国际化消息资源。
Struts 的 DispatchAction 类继承了 Action 类,此类处理请求时首先要执行 execute()
方法,然后通过控制器再转发到相应的方法进行业务处理。根据这一分析,可以在
execute()方法中对用户的身份作出验证,其实现过程如图 所示。
图 用户身份验证
如果对系统中涉及到的 Action 均编写一个验证方法,则程序代码的重复性太高,不
能体现出面向对象的设计模式,所以需将其单独封装在 BaseAction 类中,此类通过重
写 Action 类的 execute()方法对用户身份进行验证。
由于分页查询的应用比较多,所以在业务层将其封装在 BaseAction 类中,通过
getPage()方法进行实现,子类对象可以通过继承来获取此方法。getPage()方法返回一个
Map 集合对象,该集合用于装载结果集及分页条。其中,结果集对象为一页中的所有数
据集合,它是一个 List 对象;分页条为分页查询后在 JSP 页面所显示的分页信息,如记
录数、页码、上一页、下一页的超链接等,它是一个 String 类型的字符串。
getPage()方法的入口参数有四个,其中参数 hql 为分页查询的 HQL 语句,此语句不
可以包括 select 子句,它从 from 子句开始,可以传入带有占位符的 HQL,但需要通过
查询条件参数 where 传递占位符的值,当 HQL 语句没有参数时,where 参数可以设置
为 null;参数 recPerPage 为每一页的记录数;currPage 为当前的页码;action 为分页所
请求的 Action 地址。getPage()方法提供这些参数的目的在于提高程序代码的重用性,因
为在医药销售管理系统中,通过这些参数,getPage()方法已满足所有的分页查询,用到
分页查询的地方都调用了此方法。此外,在其他项目中此方法的重用价值也是非常高的。
分页查询在业务层的实现比较繁琐,因为在分页条中要考虑到国际化的实现,所以
在分页条中所有文字信息均通过 MessageResources 对象读取国际化资源文件来获取。
业务请求一 业务请求三业务请求二 业务请求四
业务处理二 业务处理三业务处理一 业务处理四
Execute()方法
验证用户身份
错误处理
验证失败
验证成功 验证成功
MessageResources 对象是 Struts 中的对象,此对象根据 Locale 信息读取相应的国际化消
息资源文件。
DeleteAction 类
公共类 DeleteAction 主要用于对项目中 LookupDispatchAction 的请求进行处理。它
继承了 LookupDispatchAction 类,重写了 execute()方法对用户的身份作出验证,当用户
身份验证失败时将进行错误处理;同时,此类还重写了 LookupDispatchAction 类中的
getKeyMethodMap()方法,添加了两个按钮对象的 key。
字符串工具类
在一个 Web 项目中,字符串是经常被操作的对象。为了简化程序的代码及提高程
序的可读性,对于经常用到的字符串处理方法,可以封装一个字符串工具类对其进行操
作。例如 JSP 页面的多选框,它提交的参数值为数组类型,在数据库的操作过程中需要
将其转换为字符串类型;在超链接中,如果加入中文参数将不能被浏览器解析,需要对
其进行一定的处理才可以使用。类似于这种操作在程序中使用的非常频繁,将其封装为
一个公共类无疑是一种较好的解决方案。
在医药销售管理系统中,封装了一个名为 StringUtil 的字符串工具类,用于对字符
的特殊处理。此类中均为静态方法。
在 HQL 语句中,如果删除多个对象可以使用 where id in(1,2,3)的方式进行删除。
arr2Str()方法用于将数组转换为字符串,可以将 JSP 表单传递 id 值转换为此种方式;
encodeURL()方法可对字符串进行 URL 编码,主要用于对含有中文的超链接进行处理;
encodeZh()方法用于对字符串中的中文乱码进行处理。
7 国际化
国际化是 Struts 的一项强大功能,它以不同国家的语言构建本地化的页面,方便不
同国家、不同语言的用户浏览访问。在医药销售管理系统中,分别构建了中文和英文两
种语言环境,根据使用者浏览器的默认语言环境呈现不同的语言显示方式。
国际化资源文件
医药销售管理系统对所有涉及到语言信息的地方均进行了国际化设置,包括 JSP 页
面文字信息及 JS 脚本提示信息等。主要包含 3 个国际化资源文件,其中属性文件为
为默认的资源文件,实例中将其设置为中文;属性文件
为 英 文 国 际 化 资 源 文 件 ;
为中文国际化资源文件。
在编写属性文件时应该注意,属性文件以 Unicode 编码,在处理中文时应该对其进
行转码。Java 提供了将中文转换为 Unicode 编码格式的工具,在命令窗口中直接输入
“native2ascii”,再输入中文,然后按回车键,将输出中文对应的 Unicode 码。
国际化实现
实例中除了对用户浏览器语言的自动匹配外,还为使用者提供了中文和英文的语言
链接,用户在使用过程中可对语言进行自动切换。此请求由 LanguageAction 类进行处理。
本地语言信息存放在 Session 会话中的 _KEY 值中,它是 Struts 的
默认配置,可以通过 Strtus 的 API 帮助文档和源码得到。对于中、英文两种请求,实例
中分别创建了中、英文所对应的 Locale 对象,并将其设置到 _KEY 值
中,实现了语言的自动切换。
8 系统登陆模块
系统登录是一个用户身份验证的过程,只有登录成功的用户才可以对系统进行操作,
否则不能对系统进行管理维护。形象地说,它就是系统的一道安全门。
查询用户
创建名为 UserDao 的类,封装对用户及系统级的数据操作。在此类中编写 login()方
法,用于根据用户名及密码查询用户对象。
在用户登录的过程中,需要判断数据库用户对象是否存在,当用户提交登录信息时,
调用此方法可返回查询后的用户对象,如果查询不到将返回 null 值。
登陆请求
用户登录请求由 LoginAction 类进行处理,此类继承了 Action 对象,它重写 execute()
方法对用户登录请求进行验证。
UserForm 对象为用户 ActionForm 对象,Struts 自动将 JSP 页面表单信息封装在此对
象中,所以可以直接获取 ActionForm 对象中的属性信息。LoginAction 类通过 UserForm
中的用户名和密码属性,调用 UserDao 对象中的 login()方法对用户信息进行查询,当数
据库中存在与之匹配的数据,则登录成功,否则登录失败。
登录页面
在 Web 文件夹的根目录中创建 文件,即系统中的用户登录页面,在其中
放置用户登录的表单。
在此页面中,首先通过<logic:notEmpty>标签判断是否存在 error 值,如果存在即表
示用户登录发生错误,将在登录页面显示错误信息。 页面运行结果如图
所示。
图 系统登录页面
9 药品类别信息管理
药品超市经营的药品众多,为方便产看、统计,需要对其进行分类。药品类别信息
管理模块主要是对药品类别信息进行统一管理,其中包括对药品类别的添加、查看、统
计等操作。
药品类别持久层设计
CategoryDao 类是药品类别的数据库操作类,它继承了 SupperDao 类,提供对药品
类别的数据库操作方法。其中 loadCategory()方法用于查询指定 id 的药品类别信息,其
入口参数为 int 型药品 id。
在添加药品信息时,需要添加与之对应的类别信息,所以还需要提供一个查询所有
药品类别信息的方法——findAllCategory()。
为方便药品类别数据的统计,实例中对药品类别中药品的数量进行统计的操作被定
义在 findCategoryAndCount(),由 HQL 语句的内连接查询进行实现。
findCategoryAndCount()方法中的 hql 属性为内连接查询语句,可对药品数量按药品
类别进行分组统计,查询后返回其结果集对象。
药品类别的添加
药品类别的添加是指将药品类别信息写入数据库,实现过程如下。
类别添加、修改请求处理
实例中将药品类别的相关请求封装在 CategoryAction 类中,此类继承了 BaseAction
对象,所以在对类别信息进行处理时,不必考虑用户是否登录的安全问题。此类中处理
添加类别信息请求的方法为 add(),由于 CategoryAction 类是一个 DispatchAction 对象,
所以当请求的参数为 add 时,将由此方法进行处理。
此方法调用了 CategoryDao 对象的 saveOrUpdate()方法,所以药品类别信息的添加
与修改操作均可通过此方法进行实现;当传递的 CategoryForm 对象含有 id 值时,则进
行修改操作。
类别添加页面
类别添加页面即 文件,此页面中主要放置了类别添加的表单。
此页面中使用 Struts 的<html:hidden>标签设置药品类别的 id 属性值,如果此属性不
为空,则意味着操作为修改操作。类别添加页面运行结果如图 所示。
图 类别添加页面
分页查看类别信息
在添加药品信息后,系统将跳转到类别信息列表页面。在此页面中将对类别信息进
行分页显示,此外还提供了药品类别修改与删除的超链接,如图 所示。
图 类别信息列表页面
查询与删除请求处理
在 CategoryAction 类中,药品类别信息的分页查询方法为 paging(),由于此类继承
于 BaseAction 类,所以调用其父类中的 getPage()方法就可以实现。它将返回结果集与分
页条对象。
在此方法中,currPage 属性为请求的页码;action 对象为 JSP 页面请求的 action 地
址;hql 为查询语句,由于它不含有占位符参数,所以 getPage()方法的条件参数设置为
null.
类别信息列表页面
是类别信息列表页面,在此页面中使用 Struts 的标签对药品类别信
息进行迭代输出。
在程序开发过程中,应尽量减少程序中 bug。例如, 页面中,在输
出 request 对象中的属性时,首先使用<logic:present>标签判断其属性是否存在。
页面中的“修改”与“删除”超链接使用 Struts 的<html:link>标签进行
设置,此标签的功能十分强大,它可以设置超链接中的参数。实例中使用的 paramName
属性用于设置所迭代的对象,paramId 属性用于设置参数的名称,paramProperty 属性用
于设置参数值,href 属性用于指定链接地址。
类别的修改与删除
在 CategoryAction 类中,类别的修改与删除相对简单一些,其中处理删除类别请求
的方法为 delete(),可根据指定的药品类别 id 删除药品类别对象。
处理修改类别信息请求的方法为 edit(),此方法通过类别 id 加载药品类别对象将类
别信息保存到 CategoryForm 对象中,最后转发到编辑页面。
此方法在加载类别信息后,会将页面转到类别添加页面,因为类别添加请求处理的
方法调用了 Hibernate 的 saveOrUpdate()方法,所以会对其进行自动更新。
药品类别统计
为了方便查看、管理药品统计信息,实例中使用了报表组件 JFreeChat 对药品分类
进行统计。其实现过程如下:
JFreeChat 工具类
创建名为 ChartUtil 的类,用于生成制图对象 JFreeChat。其中 categoryChart()方法用
于生成药品类别统计的饼形图对象,其入口参数为装载结果集的 List 集合对象。
此方法中,通过传递的 List 集合对象生成 DefaultPieDataset 数据集合,然后使用制
图工厂 ChartFactory 创建饼形图 JFreeChart 对象,并将其返回。
Action 请求
药品类别统计请求由 CategoryAction 类的 findCategoryAndCound ()方法进行处理,
此方法首先通过 CategoryDao 对象统计药品类别信息,获取结果集对象后,通过
ChartUtil 类的 categoryChart()方法生成制图对象,最后将生成的图片路径放置到 request
中。
显示报表
药品类别统计信息通过 页面进行显示,此页面通过<bean:write>
标签获取所生成图片的路径。
为避免空指针错误, 页面使用<logic:notEmpty>标签判断生成的图
片路径是否存在,其运行结果如图 所示。
图 页面
10 药品信息管理
药品信息管理主要是对药品基本信息的维护,其中包括对药品信息的添加、删除、
修改、查询等操作。
药品对象持久层设计
MedicineDao 类是药品对象的数据库操作类,它继承了 SupperDao 类,此类主要包
含 3 个方法,分别为 loadMedicine()、loadMedicineCategory()、findMedicineByMedNo()。
其中,loadMedicine()方法与 findMedicineByMedNo()方法用于根据药品 id 及药品编码查
询药品信息; loadMedicineAndCategory()方法用于查询药品信息与药品类别信息。
loadMedicineAndCategory()方法使用内连接对药品信息表与药品类别表进行联合查询,
可以减少 SQL 语句的数量。
药品实体与药品类别实体存在多对一的关联关系,当同时查看药品信息与药品类别
信息时,Hibernate 将发出两条 SQL 语句,分别为查询药品信息的 SQL 语句与查询药品
类别的 SQL 语句,所以实例中采用内连接将药品信息与药品类别信息一次加载出来,
减少了 SQL 语句,提高了数据库的性能。
药品信息的添加与修改
药品编码是药品对象的一个标识,当添加一个药品信息时,需要判断此药品是否已
经在数据库中存在,如果存在则只需更新药品的数量即可,其添加流程如图 所示。
图 药品添加流程
药品添加的请求处理
药 品 管 理 的 Action 类 为 MedicineAction , 它 继 承 于 BaseAction 类 , 是 一 个
DispatchAction 对象。此类的 findMedicineByMedNo()方法用于根据药品编码查询药品信
息是否存在,当所添加的药品编码存在时,将跳转到药品更新页面,否则跳转到药品添
加页面。
MedicineAction 类的 add()方法用于添加或修改药品信息。此方法所做的工作比较多,
包含了判断药品信息是否存在、图片上传、保存药品以及更新药品等操作。
此方法调用了 MedicineDao 类中的 saveOrUpdate()方法,因此适用于药品对象的添
加与修改操作。其中上传文件的命名采用日期时间格式,为防止重复实例中加入时间毫
秒;上传文件保存在 Web 目录的 upload 文件夹中。
添加药品
保存到数据库 更新药品数量
判断是否存在不存在 存在
药品添加页面
药品添加有 3 个页面,其中 页面提供输入药品编号的表单;当添加的
药品信息在数据库中不存在时,将通过 录入药品的详细信息;当所添加的
药品信息存在与数据库中时,经通过 页面更新药品数量,如图 所示。
图 更新药品数量
分页查看所有药品
在添加药品信息后,请求转发到查看所有药品信息,对所有药品信息进行分页显示。
此操作通过 MedicineAction 类的 paging()方法进行处理。
此方法通过调用 MedicineAction 类继承的 getPage()方法进行分页查询,在查询后分
别将结果集与分页条放置到 request 中,并转发到 页面进行显示,如图
所示。
图 页面
查看药品详细信息
在药品列表中提供了查看药品详细的超链接,此链接作用于药品名称上,单击此链
接将进入药品查看请求中,该请求由 MedicineAction 类 view()方法进行处理。
在 view()方法中,首先通过传递的药品 id 值查询药品对象,然后将查询到药品信息
放置于 request 对象中,转发到 页面进行显示,如图 所示。
图 页面
在 页面中,通过<logic:empty>标签及<logic:notEmpty>标签对药品图
片是否存在进行逻辑判断,当药品图片存在时,通过<bean:write>标签输出图片路径,
否则输出提示信息。
模糊查询药品
为方便用户查询药品,药品信息管理模块还提供了药品的模糊查询功能,即根据用
户所输入的关键字信息,对药品名称、药品描述等多个药品属性进行模糊匹配,并分页
显示模糊查询后的结果集。
药品模糊查询请求处理
药品模糊查询通过 MedicineAction 类的 blurQuery()方法进行处理。此方法根据提交
的关键词 keyWord 组合 HQL 语句,调用 getPage()方法获取查询后的结果信息对象与分
页条对象。
HQL 的模糊查询使用 like 作为关键字,此方法中分别对药品名称、药品编码、出
厂地址及药品描述进行了模糊匹配。
药品模糊查询页面
药品模糊查询页面为 ,此页面包含输入药品信息的表单。
为简化程序中的代码,此表单并没有使用 Struts 标签中的 form 表单,而采用了普通
<form>标签进行定义。此段代码在项目中是一段可以重用的代码,涉及到模糊查询时可
通过更改表单中的 action 来实现。
当在此表单中输入模糊关键词时,单击“查询”按钮,系统将进行模糊查询。例如,
查询的关键词为“感冒”,其查询结果如图 所示。
图 模糊查询药品
高级查询
使用模糊查询返回的数据结果集可能比较复杂,不方便寻找某一确切的药品。此时
高级查询便派上了用场,此查询可以根据药品的多个属性信息来查询一个确切的的药品
对象,例如输入一个药品的名称、药品编码及其他属性,可进行更为具体的查询。
实例中通过 MedicineAction 类的 query()方法对高级查询请求进行处理,此方法通
过 MedicineForm 对象构造查询条件,并调用 getPage()方法对查询后的结果集进行分页
显示。
查看库存
为了方便操作人员了解药品的库存数量,本系统中提供了对库存数量的检索功能,
即通过比较运算符查询相应的库存数量,如图 所示。
图 查看库存
MedicineAction 类的 QueryMedCount()方法用于处理库存数量的查询请求,此方法
通过参数 type 判断其查询的类型,并构造相应的 HQL 查询语句。
药品批量删除
药品批量删除操作使用 LookUpDispatchAction 对象进行处理,此操作通过 Struts 的
资源文件,映射 JSP 页面与 LookUpDispatchAction 对象之间的请求关系,其实现原理如
图 所示。
图 LookUpDispatchAction 实现批量删除
Struts 的资源文件中定义了两个 key,它们所对应的值分别为“删除所选”、“删除全
选”,二者将映射至 JSP 页面中的按钮;同时二者还对应 LookUpDispatchAction 对象中
的 Map 集合,此集合中 key 对应资源文件中的 key 值,value 对应 LookUpDispatchAction
对象中的业务方法,当单击页面中的一个按钮时,将触发 LookUpDispatchAction 对象的
相应方法。
批量删除请求处理
处理批量删除请求的类为 DeleteMedicineAction 类,它继承与 DeleteAction 类,是
一个 LookUpDispatchAction 对象,此类通过 all()方法与 selected()方法处理药品的批量删
除操作。
此 类 的 父 类 对 象 DeleteAction 重 写 了 LookUpDispatchAction 对 象 的
getKeyMethodMap()方法,它已经与 Struts 的资源文件中的 key 值进行匹配,所以此类只
需要对业务请求进行相应的处理即可。
映射 JSP 页面中的按钮
在药品信息列表页面 中,添加批量删除的表单与按钮,其中“删除所选”
与“删除全部”按钮通过<htnl:submit>标签添加。
11 购买药品
购买药品模块主要对购买药品的请求进行处理。对于用户购买药品,实例中使用了
购物车模式。当用户确定购买一个药品时,先将其添加到购物车中;接下来可以继续选
购其他药品,在选购药品结束后对其进行统一结账。这种做法不仅可以方便用户选购药
品,且能减少程序中所发出的 SQL 语句,提高数据库的性能。
选购药品
在程序中,对于用户所选购药品首先将其加到一个 List 集合中,然后再将其保存
到 Session 会话中;当用户所购买的药品发生变化时,将对 Session 会话中的对象进行操
业务方法 业务方法
Map
Key
value
LookupDispatchAction
“删除全部”按钮
“删除所选”按钮
JSP 页面
Struts 资源文件
作,该操作通过 SellAction 类的 canSellMeds()方法进行请求。
为了安全起见,程序中对于每一个购买的药品都要进行数据查询,判断其库存是否
满足用户需求,如果库存数量小于用户所需求的数量,程序将对其进行一定的错误请求。
用户选购药品后,实例中通过 页面对用户所选购的药品进行显示,此
页面为用户的订单页面,提供“删除”、“继续”、“清除”以及“结账”等超链接,其效果如图
所示。
图 订单页面
结账
对于用户结账操作,程序中通过两步来实现,首先程序要更新药品在数据库的库存
数量,然后还需要清空用户的订单信息。这一操作请求在实例中是通过 SellAction 类的
buy()方法进行处理。
在此方法中,程序还通过循环迭代用户订单中的药品对象,并在循环中判断其库存
情况是否满足用户需求,如不满足则进行相应的错误请求,最后通过 finally 块清除用户
的订单信息。
12 销售管理
销售管理模块主要用于对药品的销售信息进行管理,包括药品销售的明细管理、销
售排行统计查询等操作,其持久层操作由 SellDao 类进行处理,业务请求由 SellAction
类进行处理。
明细信息查询
本实例中,对药品销售明细的查询主要提供了两种方式,分别为查询所有销售明细
信息、查询指定时间段的销售明细信息。这两种查询请求均通过 SellAction 类进行处理,
对于查询后的结果集通过 页面进行显示,其效果如图 所示。
图 销售明细
销售排行统计
为了了解药品的销售情况以及需求信息,实例中通过 HQL 查询对药品的销售排行
进行统计,然后将销售排列在前 10 名的药品显示出来,如图 所示。
图 销售排行
销售排行统计的数据库查询方法为 sellSeq(),此方法封装在 SellDao 类中,通过
HQL 语句的连接查询对药品销售信息进行统计操作。
由于分组统计只查询了部分字段,Hibernate 所返回的数据并不是一个已封装的持久
化对象,而是一个 Object 数组对象。实例中为了便于管理及使用,将其封装为 SellSeq
对象,此方法返回装载 SellSeq 对象的 List 集合。
13 进货/需求管理
进货/需求管理模块主要用于对药品的需求信息进行增、删、改、查等数据库操作。
药品需求信息的添加与药品信息添加相类似,如果数据库中已存在所添加的药品需
求信息,则更新药品需求的数量即可,否则将录入一个新的药品需求信息到数据库中。
药品需求信息添加后由 页面进行列表显示,如图 所示。
图 页面
在此页面中,程序同样提供了药品需求的模糊查询、修改等操作,其实现方法与药
品信息管理中的类似。其中“进货完成”超链接用于对药品进货完成进行操作,当某一药
品完成进货时,可单击此超链接更新药品的库存数量,此请求由 RequireAction 类的
meded()方法进行处理。
进货完成操作实质是将药品的需求数量更新到库存中,同时清空药品的需求数量。
此方法通过加载指定药品 ID 的药品信息,查询药品库存数量与药品的需求数量,然后
通过数学运算更新药品的库存数量与药品的需求数量。
14 系统管理
系统管理模块的作用是对管理员账户进行管理及对系统进行初始化操作,在业务层
与持久层分别由 SystemAction 类与 UserDao 类进行处理。
添加管理员
添加管理员实质就是对管理员帐号信息持久化的过程。其操作比较简单,持久层可
以通过 Hibernate 框架的 save()方法添加管理员用户,在业务层由 SystemAction 类的
userAdd()方法处理此请求。
此方法首先验证了密码与确认密码是否相同,只有在密码与确认密码一致的情况下
才可以添加管理员用户。在添加管理员用户之后,由 页面进行显示,其效
果如图 所示。
图 页面
修改密码
修改密码操作需要提供旧密码,否则不能进行修改。此请求 SystemAction 类的
modifyPassowrd()方法实现。
出于程序的安全性考虑,此方法分别对用户的旧密码、新密码及确认密码进行验证,
只有符合的条件下才可以修改成功,否则程序将对其进行相应的错误处理,由
页面输出错误信息。例如用户提供了错误的原始密码,则结果如图 所示。
图 原始密码错误
系统初始化
在系统需要恢复原始状态的时候,可以通过程序提供的系统初始化操作来实现。此
操作将清除数据库中所有数据,在使用过程中要慎重。其数据库的清理操作由 UserDao
类的 initialization()实现。
Hibernate 提供的 SchemaExport 类是一个工具类,其 create()方法用于导出表操作。
实例中通过此方法进行数据的初始化操作,此过程将删除数据库中原有的数据并重新生
成。
15 运行项目
项目开发完成后,就可以在 MyEclipse 中运行该项目了。具体步骤如下:
(1)在 MyEclipse 的包资源管理器中选中 MedicineManager 项目,单击鼠标右键,
在弹出的快捷键中选择“运行方式”/MyEclipse Server Application 命令,如图 所示,
此时 MyEclipse 将对项目自动部署并运行。
图 运行 MedicineManager 项目
(2)在 Web 服务器启动成功后,MyEclipse 将通过内置的浏览器打开项目主页,
登录成功将进入系统,其运行效果如图 所示
图 实例运行结果