基于JAVA和ACCESS数据库实现的药品销售管理系统

Tempted

发布日期: 2018-11-28 07:51:44 浏览量: 2538
评分:
star star star star star star star star star star
*转载请注明来自write-bug.com

一、背景分析

药品管理系统,是反映药品购进入库、在库管理、销售出库软件系统,是医院和医药销售企业药品流动信息的传递媒介和执行依据。

然而我们在调研中发现,目前已开发出来的药品管理系统虽然在使用过程中提供了良好的药品查询及其它使用功能,但是主要是面向医院、药品生产企业和药品销售公司,并没有一款针对药品代理商的药品管理系统。药品代理商作为连接药品生产企业和医院的中间渠道,在医药流通环节扮演着举足轻重的角色。药品代理商平时需要处理大量的药品进销数据,如果不能为他们设计一款便捷的药品管理系统,将会给药品流通带来很多不便,也为药品安全埋下隐患。

此外,现有的药品管理系统在功能上还有一些缺陷,比如药品供应企业的药品生产许可证或药品经营许可证已到期,系统不能及时警示;已有的药品查询系统中不能正确区别药品的质量类别和层次。这无疑不符合药品的 GSP 管理要求,给药品管理带来不安全隐患。

基于以上原因,我们面向药品代理商,开发一款增加企业证照审核系统和药品质量类别查询的药品管理系统,给医院及医药销售企业的药品管理提供安全保障及操作方便。

二、需求分析

在第一章,我们已经分析了用户对药品管理系统的迫切需求。因此,我们需要实现一个可以满足药品代理商基本需求的应用程序。在本章将分析应用程序需要具体实现哪些功能,需要包含那些数据。

2.1 数据分析

在和一线药品销售人员交流之后,根据他们日常的进货、销售活动,我认为该应用程序应该包括以下几个方面的内容

  • 药品的基本信息
  • 生产厂家的基本信息
  • 医院的基本信息
  • 进货记录
  • 销售记录

药品的基本信息包括:药品的名称(通用名和商品名) ,批准文号,规格,生产厂家,价格等。

生产厂家的基本信息包括企业的名称,企业的批准文号,企业联系人员的姓名和联系方式,向企业付款的银行帐号信息等。

医院的基本信息包括医院名称,等级,地址,联系人员的姓名和联系方式等。

进货记录包括日期,进货的药品名称、数量、价格等。由于药品不同于其它商品,对有效期有很高的要求,进货的信息应该包括该批次药品的有效期。

销售记录包括日期,销售的药品名称、数量、价格,销售对象(医院名称)和该批次药品的有效期等。

2.2 功能分析

应用程序应该包括以下基本功能:

  • 数据的浏览
  • 数据的查询
  • 数据的插入、修改、删除
  • 简单的统计功能
  • 信息提示功能

数据的浏览应该可以对第 1 节所提到的信息进行浏览。

数据的查询应当可以根据关键字查询相应的记录。由于药品名称较长,商品名种类繁多,最好能够支持模糊查询和条件组合查询。

数据的插入、修改、删除应该对上述的信息进行添加、修改、删除操作。简单的统计功能应当可以对销售的库存、销售金额等信息进行统计,为销售人员决策提供数据支持。

信息提示功能是为保障药品质量安全,对用户予以习惯的提示。由于药品销售行业对药品的质量、有效期、年审制度要求很高,在应用程序中应该实现一些同时和警告功能。例如:对库存的过期药品进行警告;在进货时,如有年审过期的药品或药品生产企业年审过期,则不予进库;在销售表中增加药品质量属性。

2.3 其它要求

为防止用户误操作,在应用程序增加备份数据库和日志记录的功能。

此外,药品销售从业人员普遍为非计算机专业,所以应用程序应该易于安装和操作,并配有帮助手册以辅助用户。为防止用户操作失误,应用程序还要有适当的提示功能和容错能力。

三、概要设计

在第二章中,已经确定了药品销售管理系统的基本功能和所包含的数据。在本章,将对应用程序中的数据库进行设计。

3.1 数据字典

对应用程序出现的一些专业术语进行定义:

  • 药品名称:即通用名,是由世界卫生组织编定的在全球范围通用和在药品标
    准中列入的名称
  • 商品名:系指经国家药品监督管理局部门批准的特定企业使用的商品名称
  • 批准文号:生产新药或者已有国家标准的药品的,须经国务院药品监督管理部门批准,并在批准文件上规定该药品的专有编号,此编号称为药品批准文 号。批准文号=[国药准字 | 国药试字]+[H| S| J| T| F| B | Z]+8{数字}8
  • 生产批号:用于识别“批”的一组数字或字母加数字,用以追溯和审查批药品的生产历史
  • 规格:指单位剂量药品中含有药物的量
  • 包装:指单位包装箱内销售单元数
  • 药品质量类别:药品质量类别=[原研类|专利类|GMP 类|GMP 单独定价类]
  • 药品有效期:药品有效期是指该药品被批准的使用期限,表示该药品在规定的贮存条件下能够保证质量的期限
  • 药品年审:在药品实际销售过程中,由国家工商、药监部门对年审合格药品发放的相关证明。有效期一年,具体数值为年审截止日期,格式为年月日
  • 企业年审:由国家工商、药监部门对年审合格的药品生产企业发放的相关证明。有效期一年,具体数值为年审截止日期,格式为年月日
  • 医院等级:依据医院功能、设施、技术力量等对医院资质评定的指标,共分三级十等

3.2 E-R 图

根据需求分析中对应用程序所含数据的分析、数据字典的定义和数据之间的关系,可以绘制出 E-R 图(Entity-RelationshipDiagram)。

E-R 图包含了应用程序数据库中的实体和实体之间的联系。

3.3 关系数据库设计

根据 E-R 图可以分析出,应用程序中的数据库应该包括药品表、医院表、生产企业表、进货表、销售表五个基本表。每一个基本表中以药品销售活动中必要的信息作为属性。为了减少冗余和便于编程,为每一个表添加一个编号作为码。

其具体设计如下:

3.3.1 药品表

医院编号=H+3{数字}3

在医院表中,医院编号是码。分析各属性之间的关系可知,没有部分依赖和传递依赖;且只有一个码“医院编号”,所以医院表的关系模式属于 BCNF。

3.3.2 生产企业表

企业编号=F+3{数字}3

在生产企业表中,企业编号是码。分析各属性之间的关系可知,没有部分依赖和传递依赖;且只有一个码“企业编号”,所以生产企业表的关系模 式属于 BCNF。

3.3.3 进货表

进货编号=P+数字日期+3{数字}3 数字日期=8{数字}8,(例如:20111123)

进货表的码是“进货编号”。分析表中的各个属性可以发现金额还可以由单价和数量决定,造成了数据冗余。但是为方便后期程序的实现,还是保留了这一个属性。“药品编号”是进货关系的外码。由于存在传递依赖,进货 表的关系模式属于 2NF。

3.3.4 销售表

销售编号=S+日期+3{数字}3

“销售编号”是销售表的码。“药品编号”和“医院编号”是销售关系的外 码。销售表和进货表类似,销售表也存在传递依赖。所以关系模式属于 2NF。

四、详细设计

在完成了设计数据库的设计后,则进入了详细设计阶段。在本章,将设计出应用程序的用户界面、程序的基本模块和模块之间的调用关系。

4.1 用户界面设计

根据对需求的分析,我认为界面应该有以下特点:

  • 直观简洁
  • 方便操作

4.1.1 主界面

基于以上考虑,在设计用户界面时,设想把基本表的显示部分和控制按钮、查询部分放在一个界面。每一个基本表有一个对应的界面。构想参见图。 在 Java Swing 中提供了一种JTabbedPane 的界面模式,JTabbedPane 可以添 加多个 JPanel,能够做出类似于Office2007Ribbon 界面的切换卡的界面。采用切换卡界面有如下优势:

  • 所有功能有组织地集中存放,不再需要查找级联菜单、工具栏等等
  • 更好地在每个应用程序中组织命令
  • 提供足够显示更多命令的空间
  • 丰富的命令布局可以帮助用户更容易地找到重要的,常用的功能

4.1.2 查询结果显示

设置查询条件后,点击按钮可以显示查询结果。查询结果显示在对话框中的表格里,表格的格式和基本表相同。

4.1.3 新建记录

点击新建记录的按钮,可以弹出对话框进行数据的录入。点击对话框中的按钮就可以完成记录的创建。修改记录的界面与之类似。原型界面参见图。

4.2 程序调用关系

4.2.1 UML 用例图

用例图包含了系统、行为者、用例和用例之间的关系。

在药品销售管理中,行为者有药品代理商、厂商业务员、医院联系人。药品代理商可以编辑、查询应用程序中的数据记录,编辑记录功能是使用了新增记录、修改记录、删除记录三个用例。药品代理商分别通过销售用例、进货用例和医院联系人、厂家业务员联系起来。

4.2.2 数据流图

数据流图(DataFlow Diagram)是一种图形化技术,它描绘信息流和数据从输入到输出的过程中所经受的变换。根据数据流图,可以分析出程序所需的模块和模块之间的调用关系。

在药品销售管理中,在用户界面捕捉用户的操作,接受事务后数据流流向不同的模块。

4.2.3 调用关系图

将数据流图不断细化,可以转化出程序的调用关系图。

以药品页面为例,用户点击按钮,应用程序接受事务。根据按钮的不同,调用执行相应程序的模块。如果是修改数据库记录,则要根据用户的选择,调用具体的操作。修改数据记录最终要调用读、写数据库的底层模块。如果点击了关于报表的的按钮,则要先读取数据库中的记录,再调用生成报表的模块。在接收了关于统计数据的事务时,需要先读取数据库的记录,在执行相关计算的模块,得出结果。

五、 编码及实现

在本章,将记录开发应用程序中编码和调试的过程。为清晰的展示源程序的结构,本章将结合程序的 UML 类图对部分代码进行介绍。

5.1 工具选择

  • 编写语言:JAVA1.6
  • 数据库:Microsoft Office Access
  • 报表程序:JasperReport + iReport2

5.2 UML 类图

5.2.1 实现查询功能的类

共有 7 个相关的类来实现应用程序中的查询功能,UML 类图参见图:

  • BaseSQL 是基类,有受保护的静态变量 url(用来连接 ODBC)和 7 个受保 护的方法(用来实现插入、删除、更新、计算记录个数等常用功能)
  • DrugSQL (药品查询)
  • HospitalSQL(医院查询)
  • SupplerSQL(供应商查询)
  • SaleSQL (销售查询)
  • PurchaseSQL(进货查询)
  • Statistic(统计查询)

六个类继承自 BaseSQL,重写了 BaseSQL 里的方法,并根据需要的功能实现了相应的方法。

5.2.2 实现报表功能的类

这里实现报表功能主要指连接数据源。本应用程序使用了第三方开 源报表工具包JasperReport 及其设计软件 iReport。在 iReport 中定义报表 格式 xml 文件,在源程序中根据 xml 文件,实现 JasperReport 包中相应的方法即可以生成报表。 与实现 SQL 的类相似,共有 7 个相关的类来实现应用程序中的连接 报表数据源的功能,UML 类图参见图。

BaseReportDataSorce 类继承自 JDataSorce 类。JDataSorce 是 JasperReport 中提供的类,用以实现连接数 据库的功能。BaseReportDataSorce 类有若干个受保护的静态变量和方法。 DrugReportDataSorce(连接药品表)、HospitalReportDataSorce(连接医院表)、SupplerReportDataSorce(连接供应商表)、SaleReportDataSorce (连接销售表)、PurchaseReportDataSorce(连接进货表)和 Statistic(连 接 统 计 结 果 ) 六 个 类 继承 自 BaseReportDataSorce , 重 写 了 BaseReportDataSorce 里的方法,并根据需要的功能实现了相应的方法。

5.2.3 实现主界面的类

为实现在设计阶段构想的用户界面,也出于代码重用的目的,设计 了以下结构,UML 类图参见图。 MyPanel 类继承自 javax.swing.JPanel 类,有多个受保护的 JButton、JFrame、JPanel 变量,这些变量是实现每一个子界面所必要的变量,如 确认、取消按钮等。MyPanel 类还实现了 java.awt.ActionListener 接口, 用来响应按钮事件。DrugPanel(药品子界面)、HospitalPanel(医院子界 面)、SupplerPanel(供应商表子界面)、SalePanel(销售表子界面)和 PurchasePanel(进货表子界面)五个类继承自 MyPanel,重写了MyPanel 里的方法。由于统计界面和帮助界面在外观上不同,并未继承 MyPanel类,并根据需要的功能实现了相应的方法。

5.2.4 实现新建记录对话框的类

应用程序要求通过对话框来输入和显示数据,需要重新设计一个 MyDialog。UML 类图参见图。 MyDialog类继承自 javax.swing.JDialog类,有多个受保护的 JButton、 JPanel 等变量,这些变量是实现每一个子界面所必要的变量,如确认、 取消按钮等。MyDialog 类包含了必要的方法,如 Dialog 中读取数据、 将 数 据 库 中 的 数 据 写 入 Dialog 里等 。

MyDialog 类还实现了 java.awt.ActionListener 接口,用来响应按钮事件。

NewDrugDialog(药品子界面)、NewHospitalDialog(医院子界面)、NewSupplerDialog(供应商表子界面)、NewSaleDialog(销售表子界面)和NewPurchaseDialog(进 货表子界面)五个类继承自 MyDialog,重写了 MyDialog 里的方法,并根据需要的功能实现了相应的方法。

5.2.5 自定义 TableModel 类

本应用程序中实验 Java Swing 里提供的 JTable 控件来显示表格。实 现 JTable 需要指定 TableModel,用来定义表格的数据模型。由于 Java Swing 中提供的 TableModel 的结构和功能不能满足本应用程序的功能, 需要自行定义 MyTableModel 类。UML 类图参见 MyTableModel 类继承自 javax.swing.table.AbstactTableModel。

MyTableModel 中定义了两个变量:String 数组 tablehead——用来存放表头和 ArrayList\<Object\[\]\> rows——二维表格。MyTableModel 实现了多个 方法,包括添加、删除、获取表头数组等。DrugTableModel(药品表) 、HospitalTableModel ( 医 院 表 )、 SupplerTableModel ( 供 应 商 表 )、 SaleTableModel ( 销 售 表 )、 PurchaseTableModel ( 进 货 表 ) 和 BalanceTableModel(库存表)六个类继承自 BaseTableModel,在实现过程中只需变更相应的构造方法即可。

5.2.6 类之间的组织

在之前的内容,已经说明了各个功能的实现。又是如何将这些功能块组织到一起,具体实现一个模块呢?在此,以实现药品模块为例,说明如何将用户界面、查询、查询结果显示等类组织在一起。 参见图 5-6,DrugAdministration 程序主体由 MyWindow 类组成。

MyWindow 通过 JTabbedPane 控件将多个 Panel 组合在一起形成主界面, 其中包括 DrugPanel 类的对象 drugPanel。drugPanel 调用 NewDrugDialog 类的对象 dialog 来新建、修改数据记录;drugPanel 调用 DrugTableModel 类的对象 tablemodel 来定义表格;drugPanel 调用 DrugReport 类的对象 viewer 来显示报表;drugPanel 调用 DrugSQL 类的静态方法实现数据查询。

5.3 重要 SQL 查询语句

由于应用程序中不同表的插入、删除、修改的 SQL 语句类似,仅是属性 有所不同。所以这里只列出关于药品表的 SQL 语句。

  1. /*查询药品数量*/
  2. SELECT COUNT(*) FROM Drug
  3. /*查询所有药品的名称,并按升序返回*/
  4. SELECT drug_name FROM Drug ORDER BY drug_id ASC
  5. /*根据药品编号查询药品的名称*/
  6. SELECT drug_name FROM Drug WHERE drug_id = ?
  7. /*查询所有药品的记录*/
  8. SELECT * FROM Drug ORDER BY drug_id ASC
  9. /*根据药品编号查询某一药品记录*/
  10. SELECT * FROM Drug WHERE drug_id = ?
  11. /*根据药品编号删除某一药品记录*/
  12. DELETE FROM Drug WHERE drug_id = ?
  13. /*查询不同药品的销售数量*/
  14. SELECT drug_id, SUM(amount) FROM sale GROUP BY drug_id
  15. /*查询不同医院的采购数量*/
  16. SELECT hos_id, SUM(amount) FROM sale GROUP BY hos_id;
  17. /*根据药品、生产批号和有效期将进货进行分组*/
  18. SELECT drug_id, batch_num, vali_date, SUM(amount)
  19. FROM purchase
  20. GROUP BY drug_id, batch_num, vali_date;
  21. /*根据药品、生产批号和有效期将销售进行分组*/
  22. SELECT drug_id, batch_num, vali_date, SUM(amount)
  23. FROM sale
  24. GROUP BY drug_id, batch_num, vali_date;

5.4 重要代码

在程序中多次使用过convert()方法。该方法可以把JComboBox控件返回的 选中项下标转化为相应记录在供应商表中的码。例如输入数字1可以返回字 符串格式的码“F001”。

  1. private String convert(int num) {
  2. char[] c = { 'F', '0', '0', '0' };
  3. c[3] += num % 10; num /= 10;
  4. c[2] += num % 10;
  5. c[1] += num / 10;
  6. String s = new String(c);
  7. return s;
  8. }

生成查询药品的 SQL 语句。因为查询需要支持多条件复合查询,必须能 够根据用户输入的条件生成相应的 SQL 语句。Object 数组 con 存有在查询区 内获取的条件,如果条件不为空,则在 SQL 语句中加入这个条件。这样, 就可以获得多个条件的 SQL 语句。

  1. StringBuffer sb = new StringBuffer("SELECT * FROM Drug WHERE ");
  2. boolean b = false;
  3. if (con[0] != "") {
  4. sb.append("drug_name = '" + con[0] + "'");
  5. b = true;
  6. }
  7. if (con[1] != "") {
  8. if (b) sb.append(" AND ");
  9. sb.append("factory = '" + con[1] + "'");
  10. b = true;
  11. }
  12. if (con[2] != null) {
  13. if (b) sb.append(" AND ");
  14. sb.append("quality = " + con[2]);
  15. b = true;
  16. }
  17. if (con[3] != null) {
  18. if (b) sb.append(" AND ");
  19. sb.append("verification < #" + con[3] + "#");
  20. }
  21. String sql_query = new String(sb);

获取库存药品数量。purchase_amount 和 sale_amount 是均为视图,分别根据药品、生产批号和有效期对进货和销售进行分组。这两个视图就用到了 第 3 节提到的两个 SQL 语句。

视图中有四个属性:药品、生产批号、有效期和数量。获取库存药品数量的方法如下:

  1. public static Object[][] Balance() {
  2. Object[][] Pobj = null, Sobj = null;
  3. String sql_query1 = "SELECT * FROM purchase_amount";
  4. String sql_query2 = "SELECT * FROM sale_amount";
  5. try {
  6. Connection conn = DriverManager. getConnection ( url , "", "");
  7. Statement sql = conn.createStatement( ResultSet. TYPE_SCROLL_INSENSITIVE , ResultSet. CONCUR_READ_ONLY );
  8. ResultSet rs; rs = sql.executeQuery(sql_query1);
  9. rs.last(); // Move to the last row
  10. int n1 = rs.getRow(); // Last row;s number
  11. rs.beforeFirst(); // Move back to the first
  12. rowPobj = new Object[n1][4];
  13. int i = 0;
  14. while (rs.next()) {
  15. Pobj[i][0] = DrugSQL. getDrugname (rs.getString(1));
  16. Pobj[i][1] = rs.getString(2);
  17. Pobj[i][2] = rs.getDate(3);
  18. Pobj[i][3] = rs.getInt(4);
  19. i++;
  20. } rs = sql.executeQuery(sql_query2);
  21. rs.last(); // Move to the last row
  22. int n2 = rs.getRow(); // Last row;s number
  23. rs.beforeFirst(); // Move back to the first row
  24. Sobj = new Object[n2][4];
  25. int j = 0; while (rs.next()) {
  26. Sobj[j][0] = DrugSQL.getDrugname (rs.getString(1));
  27. Sobj[j][1] = rs.getString(2);
  28. Sobj[j][2] = rs.getDate(3);
  29. Sobj[j][3] = rs.getInt(4);
  30. j++;
  31. }
  32. conn.close();
  33. }
  34. catch (SQLException e) {
  35. e.printStackTrace();
  36. }
  37. for (int i = 0; i < Pobj.length; i++)
  38. for (int j = 0; j < Sobj.length; j++)
  39. if (Pobj[i][0].equals(Sobj[j][0]) && Pobj[i][1].equals(Sobj[j][1]))
  40. Pobj[i][3] = Integer. parseInt (Pobj[i][3].toString()) Integer. parseInt (Sobj[j][3].toString());
  41. Sobj = null; return Pobj;
  42. }

这两个视图的结果分别储存在二维Object数组Pobj和 Sobj 中。如果Pobj 和 Sobj 里的药品名称和生产批号相同,只可以判断是同一批的同种药品,两者之差就是库存量。

计算利润。本应用程序中可以显示近半年内的利润。一个难点是限制时间的范围是最近的半年。另外一个难点是根据进货和销售表计算利润。

计算最近六个月的代码如下。其中整数数组 month 储存的就是最近六个月月份的数值。

  1. int[] month = new int[6];
  2. Calendar cal = Calendar. getInstance ();
  3. cal.setTime(new Date());
  4. int i, m = cal.get(Calendar. MONTH ) + 1;
  5. for (i = 5; i >= 0; i--, m--)
  6. month[i] = (m + 12) % 12 != 0 ? (m + 12) % 12 : 12;

解决了限制时间范围的问题后,计算利润时先计算每个月销售的总收入,
再减去当月进货的总支出,即可以得到当月的利润。代码如下:

  1. private static String StrProf(int num, boolean isSale) {
  2. String str1 = "SELECT SUM(Sale.cost) FROM Sale WHERE sale_date >= ";
  3. String str2 = " AND sale_date < ";
  4. String str3 = "SELECT SUM(Purchase.cost) FROM Purchase WHERE pur_date >= ";
  5. String str4 = " AND pur_date < ";
  6. int[] month = new int[6];
  7. String[] strmonth = new String[7];
  8. Calendar c = Calendar. getInstance ();
  9. c.setTime(new Date());
  10. int i, y = c.get(Calendar. YEAR ), m = c.get(Calendar. MONTH ) + 1;
  11. for (i = 5; i >= 0; i--, m--)
  12. month[i] = (m + 12) % 12 != 0 ? (m + 12) % 12 : 12;
  13. for (i = 0; i < 6; i++) {
  14. StringBuffer s = new StringBuffer("#--01#");
  15. if (month[i] > c.get(Calendar. MONTH ) + 1) {
  16. s.insert(2, month[i]);
  17. s.insert(1, y - 1);
  18. }
  19. else {
  20. s.insert(2, month[i]);
  21. s.insert(1, y);
  22. }
  23. strmonth[i] = new String(s);
  24. }
  25. StringBuffer s = new StringBuffer("#--01#");
  26. s.insert(2, month[5] + 1);
  27. if (month[5] == 12) s.insert(1, (y + 1));else s.insert(1, y);
  28. strmonth[6] = new String(s);
  29. if (isSale)
  30. return (str1 + strmonth[num] + str2 + strmonth[num + 1]);
  31. else
  32. return (str3 + strmonth[num] + str4 + strmonth[num + 1]);
  33. }
  34. public static Double[] Statitic_Prof() {
  35. Double[] prof = new Double[6];
  36. String sq;
  37. try {
  38. Connection conn = DriverManager.getConnection (url , "","");
  39. Statement sql = conn.createStatement();
  40. ResultSet rs;
  41. for (int i = 0; i < 6; i++) {
  42. sq = StrProf (i, true);
  43. rs = sql.executeQuery(sq);
  44. while (rs.next()) {
  45. prof[i] = rs.getDouble(1);
  46. }
  47. sq = StrProf (i, false);
  48. rs = sql.executeQuery(sq);
  49. while (rs.next()) {
  50. prof[i] -= rs.getDouble(1);
  51. }
  52. }
  53. conn.close();
  54. }
  55. catch (SQLException e) {
  56. e.printStackTrace();
  57. }
  58. return prof;
  59. }

为了实现进货和销售时自动编号,即根据当日进货、销售数量自动编号。 比如,2012 年 1 月 1 日还没有销售记录,此时打开新建记录对话框,可以自动把销售编号编为S20120101001。于是使用 getSaleID 方法来实现以上功能。

  1. private String getSaleID(int num) {
  2. String str = null;
  3. char[] c = { '0', '0', '0' };
  4. num++; c[2] += num % 10;
  5. num /= 10; c[1] += num % 10;
  6. c[0] += num / 10;
  7. String s = new String(c);
  8. SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
  9. str = "S" + ft.format(new Date()) + s; return str;
  10. }

5.5 调试过程

在程序编写初期,每一个窗口都是独立的一个类,不仅要写大量重复的代码,还增加了出错的机会。后来,该有继承基类的方法,将每一个类重复出现的部分代码在基类中实现,使代码更加简洁,逻辑关系更加清晰。

在编码过程中,需要计算 SQL 语句执行结果的记录数以便申请合适大小 的数组。但是 Java语言不能够直接得到 ResultSet 的大小。在网上搜索到解决方法。通过移动游标,可以间接求得记录的数目,方法十分巧妙。代码如下:

先将 sql 设置为可以回滚的类型:

  1. Statement sql = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

再有以下语句:

  1. rs = sql.executeQuery(sql_query);
  2. rs.last(); // Move to the last row
  3. int n = rs.getRow(); // Last row;s number
  4. rs.beforeFirst(); // Move back to the first row

在 Access 数据库上操作有关日期的数据时,遇到一个问题是 SQL 语句 错误。后来得知在 Access 上日期是用‘#’表示,而不是其它数据库常用的 单引号。所以 SQL 语句要写成

  1. SELECT * FROM Drug WHERE verification < # ? #

而不是

  1. SELECT * FROM Drug WHERE verification < ' ? '

此外,在 Java 提供的数据类型中,日期格式有两个类,分别是 java.util.Date 和java.sql.Date,两者并不通用。比如一般日期操作用的是 java.util.Date,在数据库操作时用的是 java.sql.Date,所以在编程时要留心日期格式的转换,避免错误。

此外,在编程过程中还出现了许多小的错误,比如数组越界、数据格式转化错误……,在此不一一赘述。

通过完成这次数据库课程设计,不仅对数据库操作的相关知识有了系统的学习,对自己的编程能力、程序设计能力的提高都有很大的促进作用。

六、作品概览

6.1 功能展示

6.1.1 数据的浏览

程序主界面中,可以看到主界面由多个切换卡构成。每一个页面下有表格区、控制按钮、查询区。表格区可以显示基本表,以供用户对数据进行浏览。控制按钮由多个按钮。点击“打开表格”即可显示基本表。点击“新建记录”按钮可以在弹出的对话框中输入数据创建记录。点击“修改记录”按钮或“删除记录”按钮,可以进行修改或删除。点击“导出报表”按钮可以导出报表。在查询区,则可以输入条件进行查询。

6.1.2 数据的查询

在查询区中在查询区,有多个查询条件,可以选择填入一个或多个条件。点击“查询”,可以在基本表中查询对应的记录;点击“清空”可以清空输入的条件。查询结果将在对话框中显示。

6.1.3 数据的插入、修改、删除

在每一个页面下点击“新建记录”,可以弹出对话框,可以输入具体的数据。点击对话框内的“确认”按钮,就可以完成记录的插入。

在基本表中选择一条数据,再点击“修改记录”,可以弹出对话框,对 话框和图 6-3 所示对话框相同,只是已经填有数据库中的数据,可以对数据进行修改。点击对话框内的“确认”按钮,就完成了记录的修改。

在基本表中选择一条数据,再点击“删除记录”,可以弹出一个警告对话框,提醒用户是否确认删除。点击“确认”后,即可以记录的删除。

6.1.4 简单的统计功能

点击“打开表格” ,可以显示库存表,包括了药品名称、生产批号、有效期和库存数量在内的信息。点击“导出报表”,可以导出库存报表。

点击统计图表中的选项,可以显示对应的统计图。统计图包括:

  • 月度利润统计图(折线图)——显示近半年来每月的利润
  • 药品销量统计图(饼图)——显示各种药品销量的比重
  • 医院销量统计图(饼图)——显示各家医院采购量的比重

6.1.5 报表导出功能

应用程序中可以导出五个基本表和库存报表。报表实现了自动分页的功能。

6.1.6 备份和备份的导入

在帮助页面,可以点击“备份”按钮,可以选择一条路径备份 Access 数 据库文件。备份就是把数据库文件复制到用户选择的路径下。

点击“导入备份”,则可以将备份文件导入到应用程序中。

此外,在帮助界面中还可以点击“打开帮助文件”来打开用户手册。

6.1.7 日志记录功能

应用程序中包含一个 Record.log 文件,用来记录应用程序的数据操作日 志。记录的内容包括时间、执行操作的 SQL 语句(仅记录添加、修改和删除操作)和操作的结果(成功或失败)。如某一次操作后记录的内容如下:

6.2 不足之处

由于时间和精力有限,也由于编程能力还有待提高等原因,药品销售管理系统应用程序中还有一些不足。

一个不足是程序中数据结构的封装做的不足。程序中诸如药品、医院等数据可以封装成类,这样更加符合面向对象程序设计的要求,也可以使程序的逻辑结构更加清晰,但出于编程简单,并没有构造这些类。在日后的修改中,可以进一步将这些数据结构封装成类,另外一个不足是一些功能没有实现。比如用户需要药品进货入库时对年审过期的药品应当予以提示。但在程序中没能够实现此功能。

以上不足之处应当在日后的维护、升级过程中予以改进。

上传的附件 cloud_download 基于JAVA和ACCESS数据库实现的药品销售管理系统.7z ( 1.19mb, 135次下载 )
error_outline 下载需要12点积分

发送私信

永远别说永远,凡事都有可能

8
文章数
14
评论数
最近文章
eject