第9章图书进存销系统第9章图书进存销系统9.1项目简介本章介绍如何开发一个CS结构的图书进存销系统,该系统的主要有出版社管理、书本管理、书的入库管理、销售管理等功能,通过这些简单的功能,可以让我们了解如何利用JDBC进行数据库操作、如何使用Java的反射机制以及如何对系统进行分层等知识点。9.2建立界面在实现功能前,我们需要为这个系统建立界面和设计数据库,本小节将建立在这个小系统中所需要的各个界面。9.2.1登录界面在进入系统前,我们需要经过简单的认证才能进入,因此需要提供一个简单的登录界面,当输入用户名和密码都正确时,就可以进入系统。需要建立的登录界面如图9.1所示。图9.1登录界面界面非常的简单,只是两个输入框,一个按钮即可实现。帐号输入框使用的是JTextField类,而密码输入框使用的是JPasswordField类,使用JPasswordField对象并不会显示原始输入的字符。在本章中,我们将在最后再去实现用户的登录,先去实现系统的销售和入库功能。9.2.2销售管理界面销售管理界面主要用于进行书的销售操作,添加一本需要交易的书、从交易列表中移除该书、进行交易等操作,在本界面的上半部分为交易记录列表,我们约定交易记录列表所显示的为今天进行的交易,并提供一个输入日期的输入框,可以根据日期进行查询该天的交易记录。本界面的下半部分为显示某笔交易的具体信息,包括该笔交易所涉及的金额、销售量、交易日期、交易所涉及的书等信息。初步的界面如图9.2所示。第9章图书进存销系统·2·图9.2销售界面如图9.2,销售管理界面的交易记录列表中,每列的字段分别为该交易所涉及的书本名、总价、交易日期、总数量。销售管理界面的下面部分,是显示具体某笔交易的界面,显示对应某笔交易的总价、交易日期、总数量、交易涉及书的列表,其中交易中涉及书的列表中,包括书的书名、单价、和本次交易中该本书出售的数量。交易中涉及的书列表下,可以选择书和输入书的数量,并提供添加和删除按钮,当选择了一本书并输入相应的交易数量,再点击添加时,即可向交易涉及的书列表中添加书的记录,当然也可以进行删除操作。在界面的最上面,有一个查询按键,可以输入日期进行交易记录查询。注:具体某笔交易的界面(界面的下面部分),总价、交易日期和总数量是不可输入的,这是由于总价是由各本书的单价乘以交易数量得出来的,交易日期是当前交易时系统的时间为准的,总数量是各本书的交易数量总和,因此并不需要人手进行输入。另外,如果在书本的下拉框中选择了某本书时,将会带出该本书的单介和库存,好让使用者在操作时对该本书的状况有所了解。在本例中,每一个界面对应一个JPanel,每个界面都是一个JPanel类的子类,销售管理界面里面是一个JSplitPane对象,上面放一个个JScrollPane对象,下面部分也是一个JScrollPane对象。上面的JScrollPane对象主要存放一个JTable,下面的JScrollPane主要放一些Box对象进行布局,详细请看图书进存销系统代码清单中的SalePanel类。9.2.3入库管理界面入库管理界面和销售管理界面的布局大致相同,只是其中的数据列和文字有所差距。入加管理界面如图9.3所示。第9章图书进存销系统·3·图9.3库存管理界面与销售管理界面类似,上面的列表是入库记录,一条入库记录包括入库时所涉及的书本、入库日期和入库书本的总数量。界面下面部分是具体某条入库记录的具体信息,包括入库日期、总数量和入库书本的列表,同样地,入库日期与总数量都不可以手动输入。在新增一条入库记录时,可以向书本列表添加和删除书本,表示该入库记录中所涉及的书本及对应的数量。注:在选择某本书时,需要自动带出该书的库存。在本例中,入库管理界面对应的类为RepertoryPanel类,是JPanel的子类。9.2.4书本管理界面书本管理界面主要包括书本的查询、列表、查看等功能,书本在本例中作为基础数据的角色,主要用于销售和入库。这里需要注意的是,在新增一本书的时候,该书的库存为0,只有经过销售和入库才会对书的库存量产生影响。书的基本信息除了书名、价格介绍、所属出版社和书的种类外,还需要有书的图片,为简单起见,本例中的每本书只有一张图片,因此不需要另外建立表来存放书的图片。书本管理界面如图9.4所示。第9章图书进存销系统·4·图9.4书本管理界面书本管理界面上面的列表主要显示书本名称、简介、所属种类、出版社、库存数量和价格这些信息,此处的书本名称与销售管理(入库管理)界面中的书本名称有所区别,这里的书本名称的列宽较窄,这是由于销售(入库)中所涉及的是多本书,而书本管理界面中每一条书的记录只是代表一本书。在界面的下方有一个表单,用于查看、修改和添加书本操作,表单的右边是书的图片显示区,用于显示书本所对应的缩略图,当用户点击缩略图的时候,可以弹出新的窗口用于展示大图。与前面的界面一样,在程序中,我们新增一个BookPanel作为该界面。9.2.5种类管理界面书的种类,表示一本书是属于哪个种类的,例如计算机、文学、法律等等,这些都是书的种类,我们提供一个种类管理界面,可以用于管理各个种类。种类在本例中与书本一样,属于基础数据。新增种类并不需要任何约束,只需要输入种类的名称即可。在书的管理界面中,如果需要添加一本书,必须选择该书所对应的种类。种类管理界面如图9.5所示。第9章图书进存销系统·5·图9.5种类管理界面如图9.5所示,种类管理界面并不复杂,上面是一个简单的列表,下面是普通的查看、新增与修改的表单。在程序中,我们新增一个TypePanel作为该界面。9.2.6出版社管理界面添加一本书,除了需要有种类之外,还需要选择该书的出版社,我们提供一个出版社管理界面。如图9.6所示。第9章图书进存销系统·6·图9.6出版社管理界面出版社列表中,主要显示出版社名称、联系人、联系电话和简介这些信息,下面的表单与前面几个界面的表单类似,都是用于查看、修改和新增。在程序中,我们新增一个ConcernPanel来表示这个界面。从9.2.2到9.2.6的各个系统界面,都是存在于一个JFrame中,我们可以提供菜单,当点击了某个菜单的时候,JFrame中的各个JPanel对象隐藏,只显示对应的那个JPanel。到此,我们所需要的界面已经全部完成了,在9.2.7中我们将对各个界面的代码进行优化,再去为主界面加上相应的菜单,我们的界面就全部完成。9.2.7修改界面代码本例中涉及的各个界面,我们可以发现界面几乎都大同小异,界面上面部分是一个列表,下面是一个表单,因此,我们可以将这几个界面的共同部分提取出来,作为每个界面对象(JPanel)的父类,将一些可以重用的代码提升至父类,并可以使用“模板方法”,提供一些抽象的方法让各个子类去实现。以下代码为各个界面对象的父类(CommonPanel)的代码。代码清单:code\book\src\org\crazyit\book\ui\CommonPanel.javaprivateJTabletable;//存放数据的tableprotectedVectorVectordatas;//列表数据publicvoidsetJTable(JTabletable){this.table=table;}publicJTablegetJTable(){第9章图书进存销系统·7·returnthis.table;}publicVectorVectorgetDatas(){returndatas;}publicvoidsetDatas(VectorVectordatas){this.datas=datas;}//将数据设置进JTable中publicvoidinitData(){if(this.table==null)return;DefaultTableModeltableModel=(DefaultTableModel)this.table.getModel();//将数据设入表格Model中tableModel.setDataVector(getDatas(),getColumns());//设置表格样式setTableFace();}//刷新列表的方法publicvoidrefreshTable(){initData();getJTable().repaint();}//获取表列集合,由子类去实现publicabstractVectorStringgetColumns();//设置列表的样式,由子类去实现publicabstractvoidsetTableFace();//设置数据列表的方法,由子类去实现publicabstractvoidsetViewDatas();//清空界面下边的列表publicabstractvoidclear();//给子类使用的方法,用于获取一个列表的id列值publicStringgetSelectId(JTabletable){introw=table.getSelectedRow();intcolumn=table.getColumn(id).getModelIndex();Stringid=(String)table.getValueAt(row,column);returnid;}以上的代码,提供一个JTable的属性,这是因为每个界面中都有一个主要的列表对象,例如销售管理界面中的销售记录列表、书本管理界面中的书本列表等。注意代码中的黑体部分,都是由子类去实现的方法,getColumns()由子类去提供列表的列集合;setTableFace()是由子类去设置JTable的显示,例如需要设置某一列的宽度或者设置列表的行高等等;而setViewDatas()方法是重新去数据库读取数据,由子类去实现;clear()方法是刷新每个界面下边的表单,同样由子类去实现。在CommonPanel中提供了一个getSelectId方法,用来获得JTable属性中所选中的某一行中id列的值,也就是意味着在列表中,必须要有一个列名叫做id的列。父类定义好规范之后,子类就可以根据不同的情况,给父类不同的列,让父类进行显示,除了需要提供列的集合外,还需要提供数据,也就是CommonPanel中的datas属性。我们这里提供了一个setViewDatas的方法,主要从数据库中读取相关的数据,再调用父类的initDatas方法构建列表。那么存放各个界面对象的JFrame类中,可以提供一个方法,当界面发生转换时,就调用setViewDatas方法,具体代码如下。第9章图书进存销系统·8·代码清单:code\book\src\org\crazyit\book\ui\MainFrame.java//切换各个界面privatevoidchangePanel(CommonPanelcommonPanel){//移除当前显示的JPanelthis.remove(currentPanel);//添加需要显示的JPanelthis.add(commonPanel);//设置当前的JPanelthis.currentPanel=commonPanel;this.repaint();this.setVisible(true);//调用CommonPanel的方法重新读取数据并刷新列表commonPanel.setViewDatas();//清空界面下边的表单commonPanel.clear();}以上代码的黑体部分,调各个界面对象父类的setVieweDatas方法重新读取数据并刷新列表,各个界面中转换时,当点击了对应的菜单后,再进行转换(调用changePanel方法)。代码清单:code\book\src\org\crazyit\book\ui\MainFrame.javaprivateActionsale=newAbstractAction(销售管理,newImageIcon(images/sale.gif)){publicvoidactionPerformed(ActionE