面向对象课程设计 工资管理系统.docx
《面向对象课程设计 工资管理系统.docx》由会员分享,可在线阅读,更多相关《面向对象课程设计 工资管理系统.docx(76页珍藏版)》请在冰豆网上搜索。
面向对象课程设计工资管理系统
1需求分析
1.1课题设计目的
使用面向对象语言java设计一个员工工资管理程序,有显示、储存、显示、修改和删除功能。
每个员工有员工工号、姓名、基础工资、职务工资、奖金和工资总额。
其中员工工号不需要用户输入,存储时,数据库系统按顺序自动递增。
1.2功能要求
(1)查询功能中,用户查询时可以选择按工号查询,也可以选择姓名进行查询,也可以选择查询工资总额在某个范围内的员工的工资信息,比如查询工资总额在1000~2000的全体员工的信息,还以查询全体员工工资,并且选择按某种方式排序。
(2)修改功能中,用户可以选择修改方式,比如修改某一行,即选择修改某个员工的工资,此时需要输入修改项,即基础工资、职务工资和奖金中的一项,因为工资总额是基础工资、职务工资和奖金的综合,故不能直接修改,同时还需要输入工号,为了避免误改,所以需要确认修改后才能修改;也可以选择修改某一列,即选择修改全体员工的某一项工资,所以还需要选择修改项,其中的修改项也只有基础工资、职务工资和奖金三项。
(3)储存功能即增加用户的功能中,用户不需要输入员工工号,但必须输入员工姓名,其他几项均可以不输入,基础工资、职务工资、奖金和工资总额均被系统初始化为零。
(4)删除功能中,必须慎重操作,删除时必须输入员工工号,先查询出来,把员工的各项信息显示在下方的文本框中,在用户点击确认删除时系统就将该工号的用户的各项信息从数据库中删除。
在此说明一点,由于工资总额是员工基础工资、职务工资和奖金的综合。
基础工资、职务工资和奖金中的任意一项改变都会影响工资总额的数值,当修改频繁是,将会大大增加数据库系统的负担,且设计起来更加繁琐,所以工资总额并没有真正的储存在数据库中,每一次的查询或者其他显示工资总额的地方全都是用SQL或者HQL的函数查询语句来实现的。
1.3设计流程
设计流程采用先界面后模型
图1
1.4工资表模式
根据上述目的和各项功能要求,选择如表1的数据库表来储存员工各项工资信息其中的Id号即为员工工号。
表1
ID
姓名
基础工资
职务工资
奖金
3
张三
5000
2000
3000
……
……
……
……
……
1.5开发环境
JDK1.6
Myeclipse6.5
Mysql5.22
Hibernateannotation3.4
测试工具:
junit4.7
注明:
(1)在详细设计中的代码均为局部的关键代码,完整代码均在附录里;
(2)数据库里的信息只为了测试,与其含义没有关系;
(3)所有模块的模样图中,圆角框表示容器,直角框表示组件。
2详细设计
2.1外层模块设计
2.1.1外层模块模样
根据个人设计思路,设计的外侧模块的模样如图2
图2
外侧模块设计,首先新建一个叫MyApplet的类,并继承java下applet包中的Applet类,在这里,也可以自己定义一个自己的框架的类,去继承Frame类,但是简单起见,我就定义了自己的框架的类,并继承了Applet类,这样有些Applet已经实现的功能就不需要我自己去实现了,比如当你点击这个类运行而得的窗口的右上角的“X”时,窗口就关闭了,如果没有继承Applet类,那么这些功能将由自己实现,查看java的那套api会发现里面有个一属性常量,给定义的窗口设置该属性就可以解决。
参考印旻主编的《java与面向对象程序设计教程》第八章的布局设计可知:
FlowLayout的布局方式虽然非常简单,但是这种布局的容器会将容器的里的组件按照加入的顺序一个个从左往右,从上往下的排列。
这样的布局显然不合适,也不美观。
而BorderLayout则将整个容器分为东、西、南、北、中,这样的布局比较死,限制了设计者自己定义布局的功能。
GridLayout的布局形式,虽然给了设计者自己定义布局的一部分功能,但是还是存在很大一部分的限制,还有CardLayout(卡片布局设计)和GridBagLayout,卡片布局设计显然是可以采用的,但是不能只用卡片布局设计,因为只用它显得单一,而且功能不全。
剩下的GridBagLayout的布局设计是很适合我想象的布局的,因为这种布局设计给了设计者很大的自定义空间,并且各个行或者列的大小都可以由设计者自己指定,也不要求容器中的组件按个空格地放。
经过上述外层模块布局设计的分析,最适合外层模块布局设计的方式就是GridBagLayout。
GridBagLayout布局设计方式的使用步骤如下:
(1)创建GridBagLayout的对象;
(2)将容器的布局设置成这个对象;
(3)创建GridBagConstraints对象,并指定其各项属性;
(4)设置GridBagConstraints对象和组件的关联;
(5)将组件加入容器中。
为了使窗口中的标签和文本框等东西的大小可以随窗口的变大而变大,或者缩小而缩小,所以在外层容器里面的组件不是直接加入外层容器的,本质是在外层容器中加入子容器,然后在子容器中加入组件。
外层容器的对子容器放置的布局是GridBagLayout布局设计,而子容器中又使用简单布局设计。
所以整体上是使用混合布局设计,这样可以实现更多的界面设计样式。
2.1.2外层模块代码解析
(1)MyApplet类继承Applet,所以本身就是一个容器,不需要自己再去创建外层容器了,就把this(本容器)当成外层容器就可以了。
对本容器采用GridBagLayout的布局设计,按照上述的步骤:
创建GridBagLayout布局对象,即GridBagLayoutgbLayout=newGridBagLayout();
设置本容器为该布局对象,即this.setLayout(gbLayout);
(2)创建一个大小为3的Panel数组p,并实例化三个Panel。
(3)创建一个显示系统名称的Label类型的tittle,设置其中字体的大小和颜色,并将
Label加入到Panel[0]中的语句分别是:
Labeltittle=newLabel("工资管理系统");
tittle.setFont(newFont("Serif",50,50));tittle.setBackground(Color.GREEN);p[0].add(tittle);
并且对Panel[0]采用Gridlayout的布局设计,由于只需添加标题这样一个组件就可以了,所以设置为一行一列:
p[0]=newPanel(newGridLayout(1,1))。
并用GridBagLayout的布局设计将Panel1加入到容器MyApplet中,具体实现代码如下:
gbc.gridwidth=GridBagConstraints.BOTH;//占据横向剩余空间
gbc.weightx=1;//横向可扩展
gbc.gridwidth=GridBagConstraints.REMAINDER;
gbLayout.setConstraints(p[0],gbc);//将gridbagconstraints对象与组建相联系
add(p[0]);
(4)用GridLayout的布局设计分别将查询按钮、储存按钮、修改按钮和删除按钮加入Panel[1]中,然后用GridBagLayout的布局设计将Panel[1]加入MyApplet中。
具体过程是定义各一个四个元素的Button类型的数组,并实例化其中每个元素。
参数分别为“查询”、“储存”、“修改”和“删除”。
并依次将该数组的每个按钮加入到Panel[1]中。
其实现代码如下:
Button[]b=newButton[4];
b[0]=newButton("查询");
b[0].addActionListener(this);//注册监听
b[1]=newButton("储存");
b[1].addActionListener(this);
b[2]=newButton("修改");
b[2].addActionListener(this);
b[3]=newButton("删除");
b[3].addActionListener(this);
p[1]=newPanel(newGridLayout(1,4));
for(inti=0;i<4;i++){
p[1].add(b[i]);
p[1].add(newLabel(""));//将按钮分开
}
gbc.insets=newInsets(20,4,4,4);
gbLayout.setConstraints(p[1],gbc);
add(p[1]);
(5)初始化的Panel数组的第三个元素p[3]采用卡片的布局设计,卡片设计的显示形式是让要显示的东西像扑克一样叠起来,每次都只能显示最表面的一张,其他的都在下方,不显示。
目的是使得查询模块、储存模块、修改模块和删除模块以卡片的形式显示在四个选择功能的按钮下方。
让页面看起来简洁、清晰、明朗。
CardLayout的使用步骤:
(1)创建一个CardLayout对象作为布局编辑器:
Mycard=newCardLayout();
(2)将容器p[3]设置为Mycard的布局:
p[3].setLayout(Mycard);
(3)将p[3]加入MyApplet中;
(4)设置中各组件的显示方式。
本设计中,p[3]中各组件的显示方式只有设置为按名显示最为适合,窗口的显示如图3,创建到显示的实现代码如下:
QueryPanelqp=newQueryPanel();//查询模块
addPanelap=newaddPanel();//增加用户模块
updatePanelup=newupdatePanel();//修改模块
deletePaneldp=newdeletePanel();//删除模块
p[2]=newPanel(myCard);
p[2].setLayout(myCard);
p[2].add(qp,"查询");
p[2].add(ap,"储存");
p[2].add(up,"修改");
p[2].add(dp,"删除");
gbc.insets=newInsets(20,4,4,4);
gbLayout.setConstraints(p[2],gbc);
add(p[2]);
//事件处理:
当用户点击四大功能按钮时,下方显示对应的功能的子模块
publicvoidactionPerformed(ActionEvente){
myCard.show(p[2],e.getActionCommand());
}
图3
2.1.3外层模块事件处理
(1)分别将查询按钮、储存按钮、修改按钮和删除按钮注册给监听器,并在类头的继承类后面加上implementsActionListener实现接口ActionListener之后,重写接口里定义的抽象方法publicvoidactionPerformed(ActionEvente);在该方法里设计按名显示功能模块的程序,即
publicvoidactionPerformed(ActionEvente){
myCard.show(p[2],e.getActionCommand());
}
2.2查询模块设计
2.2.1查询模块模样
查询模块的模样如图4所示。
图4
查询模块的设计,新建一个叫QueryPanel的java类,这各类也继承了Applet类,所以本身就是一个容器。
并对本容器设置GridBagLayout的布局设计,从上往下,加入三个子容器。
第一个叫select,用来装载查询方式下拉框、查询范围下拉框、排列下拉框、排序下拉框和查询按钮;第二个容器id,作用是当用用户在select容器中的查询方式选择为“按工号查询”时,光标跳转到id容器的id输入框,之后,当用户点击“按工号查询”按钮时,结果显示文本框中显示用户输入的id号即工号的员工的工资信息;第二个容器叫name,作用是当用户点击按姓名查询的时候,光标跳转到提示输入姓名的标签的后面的输入框中,同第二个一样,当用户点击“按姓名查询”按钮后,所输入姓名的员工的工作信息会显示在下方的文本里;最下方的就用文本框了,作用上述已经说明了。
缺省情况下,即用户什么都没有选择的情况下,直接点击“查询”按钮后,将显示全体员工的工资信息。
查询方式下拉框中有按工号、按姓名和默认全部的选项;查询范围的下拉框中有各个阶段范围的对应选择,默认是范围不限;排列下拉框中有按基础工资、职务工资、奖金、工资总额和默认是工号的选项;排序下拉框中就升序和降序两种选择,默认是升序排序。
这些下拉框的中的每一个选项都是任由用户选择的,但是选择的项不能相互矛盾,比如选择了按工号查询,就不能在输入姓名的输入框中输入信息。
这些跳转控制,在事件处理中有详细的设计。
布局设计的代码和外层模块设计的完全一样,不再重复,代码中有注明,下拉框是用一个Choice类型的数组来表示的,窗口显示如图5。
实现下拉框的代码如下:
Choicec[]=newChoice[5];//下拉框数组
for(inti=0;i<4;i++)
{
c[i]=newChoice();
c[i].addItemListener(this);
select.add(c[i]);
}
c[0].add("查询方式");
c[0].add("按工号");
c[0].add("按姓名");
c[0].add("默认是全部");
c[1].add("查询范围");
c[1].add("0-2000");
c[1].add("2000-5000");
c[1].add("5000-8000");
c[1].add("800-10000");
c[1].add("10000-20000");
c[1].add(">20000");
c[1].add("默认全部");
c[2].add("排列");
c[2].add("按工资总额");
c[2].add("按基础工资");
c[2].add("按职务工资");
c[2].add("按奖金");
c[2].add("默认按工号");
c[3].add("排序");
c[3].add("升序");
c[3].add("降序");
c[3].add("默认升序");
图5
2.2.2查询模块事件处理
该模块中共有四个下拉框,一个工号输入框,一个姓名输入文本框和一个现实文本框,第一个个查询方式下拉框。
(1)当用户选择的是查询方式或者默认全部时,系统将查询的对象定位整个员工工作表;第二个是供用户可以选择查询的范围的下拉框,这里的范围是指工资总额在所在的范围,比如用户选择8000~10000则表示用户选择了工资总额在8000~10000的员工,上下限选择均包括端点值;第三个是排列下拉框,表示用户选择按什么什么数值排列,结合第四个排序下拉框的意思就是用户选择按什么的数值以什么的顺序排列;这四个下拉框均有默认值,用户不显示的做任何选择,当用户直接点击查询按钮时,系统将查询全部员工则工资信息,按工号的升序排列打印在显示文本框。
(2)当用在查询方式下拉框中选择按工号查询时,系统自动跳转到工号输入框,提示用户输入员工工号,然后点击按工号查询按钮,系统查询用户所输入的工号的工资信息,并打印到显示文本框。
关键代码如下:
if(c[0].getSelectedIndex()==0||c[0].getSelectedIndex()==3)//选择查询方式
c[1].requestFocus();
elseif(c[0].getSelectedIndex()==1){
inputId.requestFocus();
inputId.setText("转到这里");
inputName.setText("");
}
(3)当用户在查询方式下拉框中选择按姓名查询时,系统将自动跳转到姓名输入框,提示用户输入姓名。
elseif(c[0].getSelectedIndex()==2){
inputName.requestFocus();
inputName.setText("转到这里");
inputId.setText("");
}
2.3储存模块设计
2.3.1储存模块模样
储存模块的模样如图6所示。
图6
储存模块的设计,新建一个叫AddPanel的java类,继承了Applet类,采用的布局设计和查询模块的完全一样,不再赘述。
在储存子容器中添加去的是三个Panel。
第一个是用来显示提示性标签的,即显示姓名、基础工资、职务工资、奖金、输入对应信息,其作用是提示用户根据提示,在对应的输入框中输入合法的信息;第二个Panel就是在第一个提示标签的下方添加相对应的输入框,以便用户对应输入信息,这个Panel的右端添加了两个按钮,前一个是“增加员工”,是往数据库存数据的事件源,第二个按钮是“清空”,用来清空全部输入框中残留的信息;第三个就是一个文本框,作用就是显示新增员工的信息。
其中的提示性标签是用Label数组来实现的,并且在中间加入了空的标签,目的是是标签分开,不至于排列太紧密,影响美观,窗口显示如图7。
实现代码如下:
L[0]=newLabel("姓名");
L[1]=newLabel("基础工资");
L[2]=newLabel("职务工资");
L[3]=newLabel("奖金");
L[4]=newLabel("输入对应信息");
for(inti=0;i<4;i++)
{
t[i]=newTextField();
tPanel.add(t[i]);
LPanel.add(L[i]);
}
tPanel.add(add);
tPanel.add(re);
tPanel.add(newLabel(""));
LPanel.add(L[4]);
LPanel.add(newLabel(""));
LPanel.add(newLabel(""));
2.3.2储存模事件处理
本模块共有四个输入文本框,一个增加员工按钮,一个清空按钮和一个显示文本框。
当用用户点击增加员工按钮时,系统将读取四个输入文本框中的内容,在姓名不为空,三项金额为整数的情况下,系统将员工信息存入数据库,并在下方的显示文本框中打印刚增加的员工的工号、姓名和工资信息。
当用户点击清空按钮时,系统将四个输入文本框中的残留信息全部清空。
其中的flag不只是在这两个地方处理,在讨论异常的时候会详细介绍。
操作实例如图7所示。
这段内容的关键代码如下:
booleanflag;
if(e.getSource()==re)
for(inti=0;i<4;i++)
t[i].setText("");
if(e.getSource()==add)//插入数据
{
flag=true;
if(t[0].getText().equals("")){
flag=false;
result.setText("增加用户失败:
必须输入用户名!
");
}else
name=t[0].getText();
if(flag){
HibernateOperateq=newHibernateOperate();
q.testsave(name,basicWage,postWage,bonus);
}
图7
2.4修改模块设计
2.4.1修改模块模样
修改模块如图8所示。
图8
修改模块的设计,新建一个叫UpdatePanel的java类,布局设计同上。
修改子容器比较简单,里面就装有个一子容器select,容器select中添加了下拉框“修改方式”、下拉框“修改项”、标签“输入新值”、工号输入框、标签“输入新值”、新值输入框、修改按钮。
修改方式中有修改行和修改列两个选项;改项中可以选择的只有基础工资、职务工资和奖金;由于是修改,所以每项都必须输入或者选择,否则不执行操作。
该模块中各部分的实现代码前面均有提到过,不再赘述,窗口显示如图9所示。
图9
2.4.2修改模块事件处理
当用户点击主模块中的修改按钮时,下方将显示修改模块的界面。
修改界面中结构比较简单,两个下拉框和两个输入文本框,两个下拉框分别是修改方式的选择和修改项的选择。
(1)修改方式中有修改行和修改列两种选择,修改行是修改一行,然后选择修改项,这种情况必须输入工号,新值在不输入的情况下将以0为缺省型,但是不推荐。
(2)当用户选择的修改方式为修改列时,不需要输入工号,此时,工号输入框不能进行输入,只要为输入框设置属性setFocusable(false);即可;当用户选择修改行时重置过来即setFocusable(true);即可。
(3)做完
(1),
(2)的选择后,用户点击修改按钮时,系统将弹出确认修改的对话框,让
用户选择是都确认修改,如果用户点击对话框上的确认,系统将执行修改。
如果修改成功,系统将会弹出修改成功的对话框。
操作实例如图9,关键代码如下:
introw;
if(e.getActionCommand()=="修改"){
try{
num=Integer.parseInt(no.getText());
}catch(NumberFormatExceptione2){
num=-1;
}
try{
newValue=Integer.parseInt(data.getText());
}catch(NumberFormatExceptione1){
newValue=-1;
}
if(or==1&&!
colum.equals("xx")&&num>=0&&newValue>=0){//选择的是修改行
y_n=newDialog(this.y_n,"确定修改?
",true);
//实例化一个对话框
Panelp1=ne