项目说明
本项目是依据《轻量级 java ee 企业应用实战 第4版》的最后一章中的项目实现的,原本项目使用的框架是struts2 + spring 4 + hibernate,因为本人在学习spring mvc + spring + mybatis,所以将它重写了一次,使用了spring mvc + spring + mybatis项目。在正文中介绍项目的时候,也将主要依据原书的叙述。
因为项目是根据原始项目实现的,实现过程中可能出现有bug,如果发现问题可以与我联系,或在评论区中留言评论。
零,准备工作
首先根据建立参考链接ssm基本项目;也可以直接从github上直接下载, 下载之后, 在目录initproject下面有一个hrsystem项目,这个项目就是初始项目了。这个项目是根据前面提供的链接实现的,整合了基本的ssm框架,直接部署tomcat就可以运行了,部署方式可以直接参考前面的链接。该项目下还有一个目录就是originalproject,该目录存放的是原书中的项目代码,也是本文代码的参考实现。
github地址
hrsystem:https://github.com/sysukinthon/hrsystem(包含项目初始项目和原始ssh项目)
hrsystem_dev:https://github.com/sysukinthon/hrsystem_dev(包含完整的ssm项目代码)
上面的项目都是idea项目,下载到相应的项目后,运行步骤如下:
- 在idea中打开
- 建立下数据库,数据库使用mysql,sql文件在src/main/resource目录下,叫做schema.sql。
- 修改下项目中的spring-mybatis.xml里面关于数据库的配置,主要修改用户名和密码。
- 上述都配置好后,再配置一下tomcat就可以了。
一,项目背景及系统结构
1)应用背景
项目实现的是一个简单的工作流系统,该系统包含公司日常的事务:日常考勤,工资结算及签核申请等。该签核系统完成了考勤改变申请的送签,以及对申请的签核,这是一种简单的工作流,,可以提高企业的生产效率,另外,本应用额外的打卡系统,自动工资结算等,也可以在一定程度上提高企业的生产效率。
2)系统功能介绍
系统的用户主要分为两种:普通员工和经理。
普通员工的功能包括
- 员工通过打卡完成每天上下班的考勤记录,考勤记录包括迟到,早退,旷工等;
- 员工也可以查看本人最近3天的考勤情况;
- 如果发现考勤情况与实际不符,可提出申请,申请将由系统自动转发给员工经理,如果经理通过核准,则此申请自动生效,系统将考勤必为实际的情况;
- 员工也可以查看自己的工资记录
经理的功能包括
- 包含上述普通员工的功能,但是经理的考勤不能提出申请;
- 签核员工申请
- 新增员工
- 查看管理的全部员工
- 查看员工的上月工资
3)系统结构
- 表现层:由jsp页面组成
- mvc层:使用mvc框架技术(spring mvc)
- 业务逻辑层:主要由spring ioc容器管理的业务逻辑组件组成(门面模式)
- dao层:由6个dao组件组成
- 领域对象层:由7个持久化对象组成(使用贫血模式设计)
- 数据库服务层:使用mysql数据库存储持久化数据
4)系统功能模块
本系统可以大致分为两个模块:经理模块和员工模块,其主要业务逻辑通过empmanagerservice和mgrmanagerservice两个业务逻辑组件来实现,因此可以使用这两个业务组件来封装dao组件。
系统以业务逻辑组件作为dao组件的门面,封装这些dao组件,业务逻辑组件底层依赖于这些dao组件,向上实现系统的业务逻辑功能
本系统主要有如下6个dao对象
- applicationdao:提供对application_inf表的基本操作
- attenddao:提供对attend_inf表的基本操作
- attendtypedao:提供对attend_type_inf表的基本操作
- checkbackdao:提供对checkback_inf表的基本操作
- employeedao:提供对employee_inf表的基本操作
- paymentdao:提供对payment_inf表的基本操作
系统提供了两个业务逻辑组件:
- empmanagerserivce:提供employee角色所需业务逻辑功能的实现
- mgrmanagerservice:提供manager角色所需业务逻辑功能的实现
二,持久层设计
1)设计持久化实体
面向对象分析,是指根据系统需求提取应用中的对象,将这些对象抽象成类,再抽取出需需要持久化保存的类,这些需要持久化保持的类就是持久化对象(po)。
本项目一共设计了7个持久化类
- application: 对应普通员工的考勤提出申请,包含申请理由,是否被批复及申请改变的类型等属性
- attend: 对应每天的考勤,包含考勤时间,考勤员工,是否上班及考勤类别等信息
- attendtype: 对应考勤的类别,包含考勤的名称,如迟到,早退等
- checkback: 对应批复,包含该批复对应的申请,是否通过申请,由哪个经理完成批复等属性
- employee: 对应系统的员工信息,包含员工的用户名,密码,工资以及对应的经理等属性
- manager: 对应系统的经理信息,公包含经理管理的部门名。实际上,manager继承了employee类,因此该类同样包含employee的所有属性
- payment: 对应每月所发的薪水信息,包含发薪月份,领薪员工和薪资数等信息
本应用采用贫血模式来设计它们,所以持久化类中不提供业务逻辑方法,而是将所有的业务逻辑方法放到业务逻辑组件中实现。
当采用贫血模式的架构模型时,系统中的领域对象十分简洁,它们都是单纯的数据类,不需要考虑到底应该包含哪些业务逻辑方法,因此开发起来非常便捷;而系统的所有的业务逻辑都由业务逻辑组件负责实现,可以将业务逻辑的变化限制在业务逻辑层内,从而避免扩散到两个层,因此降低了系统的开发难度。
7个po的关系如下:
- employee是manager的父类,同时manager和employee之间存在 1-n的关系,即一个manager对应多个employee,但每个employee只能对应一个manager
- employee和payment之间是1-n的关系,即每个员工可以多次领取薪水
- employee和attend之间存在1-n的关系,即每个员工可以参与多次考勤,但每次考勤只对应一个员工
- manager继承了employee类,因此具有employee的全部属性,另外manager还不慌不忙 checkback之间存在1-n的关系
- application与attend之间存在n-1的关系,即每个attend可以被对应多次申请。
- application与attendtype之间存在n-1的关系,即每次申请都有明确的考勤类型,而一个考勤类型可以对应多个申请
- attend与attendtype之间存在n-1的关系,即每个attend只属于一个attendtype。
根据上面书写如下的schema.sql,也就是数据库文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
create database if not exists hrsystem collate = 'utf8_general_ci' character set = 'utf8' ;
use hrsystem;
create table attend_type_inf
(
type_id int auto_increment,
amerce_amount double not null ,
type_name varchar( 50 ) not null ,
primary key(type_id)
);
create table employee_inf
(
emp_id int auto_increment,
emp_type int ,
emp_name varchar( 50 ) not null ,
emp_pass varchar( 50 ) not null ,
emp_salary double not null ,
mgr_id int ,
dept_name varchar( 50 ),
primary key(emp_id),
unique key(emp_name),
foreign key(mgr_id) references employee_inf(emp_id)
);
create table attend_inf
(
attend_id int auto_increment,
duty_day varchar( 50 ) not null ,
punch_time datetime,
is_come boolean not null ,
type_id int not null ,
emp_id int not null ,
primary key(attend_id),
foreign key(type_id) references attend_type_inf(type_id),
foreign key(emp_id) references employee_inf(emp_id)
);
create table application_inf
(
app_id int auto_increment,
attend_id int not null ,
app_reason varchar( 255 ),
app_result boolean ,
type_id int not null ,
primary key(app_id),
foreign key(type_id) references attend_type_inf(type_id),
foreign key(attend_id) references attend_inf(attend_id)
);
create table payment_inf
(
pay_id int auto_increment,
pay_month varchar( 50 ) not null ,
pay_amount double not null ,
emp_id int not null ,
primary key(pay_id),
foreign key(emp_id) references employee_inf(emp_id)
);
create table checkback_inf
(
check_id int auto_increment,
app_id int not null ,
check_result boolean not null ,
check_reason varchar( 255 ),
mgr_id int not null ,
primary key(check_id),
foreign key(app_id) references application_inf(app_id),
foreign key(mgr_id) references employee_inf(emp_id)
);
insert into `test_user` values ( '1' , '123455@qq.com' , '12345' , 'test' );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '正常' , 0 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '事假' , - 20 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '病假' , - 10 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '迟到' , - 10 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '早退' , - 10 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '旷工' , - 30 );
insert into attend_type_inf ( type_name , amerce_amount)
values ( '出差' , 10 );
# 插入经理
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id , dept_name)
values ( 2 , 'oracle' , 'oracle' , 5000 , null , 'db部' );
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id , dept_name)
values ( 2 , 'weblogic' , 'weblogic' , 6000 , null , 'server部' );
# 员工
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id)
values ( 1 , 'mysql' , 'mysql' , 3000 , 1 );
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id)
values ( 1 , 'hsql' , 'hsql' , 3200 , 1 );
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id)
values ( 1 , 'tomcat' , 'tomcat' , 2800 , 2 );
insert into employee_inf (emp_type , emp_name , emp_pass , emp_salary , mgr_id)
values ( 1 , 'jetty' , 'jetty' , 2560 , 2 );
|
上面已经陈述了全部的设计,剩下的一些细节将在下面的代码实现中说明。
三,model层
为了节约篇幅,下面的所有实现都只针对employee类来说明,如有必要会针对其他进行说明
持久化实体类的存放目录是com.kevin.hrsystem.model,下面是employee持久化类的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package com.kevin.hrsystem.model;
public class employee {
private long id;
private int type;
private string name;
private string password;
private double salary;
private manager manager;
public long getid() {
return id;
}
public void setid( long id) {
this .id = id;
}
public int gettype() {
return type;
}
public void settype( int type) {
this .type = type;
}
public string getname() {
return name;
}
public void setname(string name) {
this .name = name;
}
public string getpassword() {
return password;
}
public void setpassword(string password) {
this .password = password;
}
public double getsalary() {
return salary;
}
public void setsalary( double salary) {
this .salary = salary;
}
public manager getmanager() {
return manager;
}
public void setmanager(manager manager) {
this .manager = manager;
}
@override
public string tostring() {
string rsl = "employee [id=" + this .id + ", name=" + this .name + ", password=" + this .password + ", type=" + this .type + ", salary=" + this .salary;
if ( this .manager != null ) {
rsl += ", managerid=" + this .manager.getid() + ", managername=" + this .manager.getname() + "]" ;
}
return rsl;
}
}
|
在这里针对employee.java和manager.java进行一点说明,这两个的数据库表都是employee_inf,但是employee没有dept_name(部门名称),而manager没有mgr_id(所属部门经理id)
其他的model对象这里就不多说,直接参考源码即可。
四,dao(data access object)层
1)dao组件的定义
在持久层之上,可以使用dao组件再次封装数据库操作,这也是java ee应用里常用的dao模式。当使用dao模式时,既体现了业务逻辑组件封装dao组件的门面模式,也可分离业务逻辑组件和dao组件的功能:业务逻辑组件负责业务逻辑的变化,而dao组件负责持久化技术的变化,这也正是桥接模式的使用。
引入dao模式后,每个dao组件包含了数据库的访问逻辑;每个dao组件可对一个数据库表完成基本的curd等操作。
dao模式是一种更符合软件工程的开发方式,使用dao模式有如下理由:
- dao模式抽象出数据访问方式,业务逻辑组件无须理会底层的数据库访问细节,而只专注于业务逻辑的实现,业务逻辑组件只负责业务功能的变化
- dao将数据访问集中在独立的一层,所有的数据访问都由dao对象完成,这层独立的dao分离了数据访问的实现与其他业务逻辑,使得系统更具可维护性
- dao还有助于提升系统的可移植性,独立的dao层使得系统能在不同的数据库之间轻易切换,底层的数据库实现对于业务逻辑组件是透明的。数据库移植时仅仅影响dao层,不同数据库的切换也不会影响业务逻辑组件,因此提供了系统的可复用性
dao组件提供了各持久化对象的基本的crud操作,而在dao接口里则对dao组件包含的各种crud方法提供了声明。使用dao接口的原因是:避免业务逻辑组件与特定的dao组件耦合
尽管很多的dao组件方法需要根据业务逻辑需求的变化而变化,但是还是有一些通用的方法,在代码实现中,basedao接口包含了几个通用的方法,其定义如下:
1
2
3
4
5
6
7
8
9
|
package com.kevin.hrsystem.dao;
import java.util.list;
public interface basedao<t> {
void save(t entity); //保持持久化实例
void delete( long id); //根据主键删除持久化实例
void update(t entity); //更新持久化实例
t findbyid( long id); //根据主键加载持久化实例
list<t> findall(); //获取数据表中全部的持久化实例
}
|
dao接口无须给出任何实现,仅仅是dao组件包含的crud方法的定义,这些方法定义的实现取决于底层的持久化技术,dao组件的实现既可以使用传统的jdbc,也可以采用hibernate,mybatis等技术。
如下是我们的employeedao组件接口的源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.kevin.hrsystem.dao;
import com.kevin.hrsystem.model.employee;
import com.kevin.hrsystem.model.manager;
import org.apache.ibatis.annotations.param;
import java.util.list;
public interface employeedao extends basedao<employee>{
/**
* 根据用户名和密码查询员工
* @param name 用户名
* password 密码
* @return 返回员工
*/
public employee findbynameandpass( @param ( "name" )string name, @param ( "password" ) string password);
public employee findbyname( @param ( "name" )string name);
public list<employee> findemployeesbymgrid( @param ( "id" ) long id);
public void saveasemployee(employee employee);
public void saveasmanager(manager manager);
}
|
其他的dao组件接口的源码请直接查看代码;这里有一个要明确的,就是持久化对象里面有employee和manager,但是dao组件里面只有employeedao,因为这两个持久化对象对应的其实是同一个数据库表,在实现的过程中,我将两个持化对象的crud整合到同一个dao组件里面了。
dao接口只定义了dao组件应该实现的方法,但如何实现这些dao方法则没有任何限制,程序可以使用任何持久化技术来实现它们,这样就可以让dao组件来负责持久化技术这个维度的变化,当系统需要在不同的持久化技术之间迁移时,应用只需要提供不同的dao实现类即可,程序的其他部分无须进行任何改变,这就很好地提高了系统的可扩展性。
2)dao组件的实现
在本项目中,dao层的实现是使用了mybatis技术,在基础项目中, 我们已经在spring中引入了mybatis,其配置文件(spring-mybatis.xml)如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
<?xml version= "1.0" encoding= "utf-8" ?>
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi= "http://www.w3.org/2001/xmlschema-instance"
xmlns:context= "http://www.springframework.org/schema/context" xmlns:tx= "http://www.springframework.org/schema/tx"
xsi:schemalocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" >
<!--扫描service包下所有注解的类型-->
<context:component-scan base- package = "com.kevin.hrsystem.service" />
<!--配置数据库相关参数properties的属性-->
<context:property-placeholder location= "classpath:jdbc.properties" />
<!--配置数据源-->
<bean id= "datasource" class = "com.mchange.v2.c3p0.combopooleddatasource" >
<property name= "driverclass" value= "${jdbc.driver}" />
<property name= "jdbcurl" value= "${jdbc.url}" />
<property name= "user" value= "${jdbc.username}" />
<property name= "password" value= "${jdbc.password}" />
<property name= "maxpoolsize" value= "${c3p0.maxpoolsize}" />
<property name= "minpoolsize" value= "${c3p0.minpoolsize}" />
<property name= "autocommitonclose" value= "${c3p0.autocommitonclose}" />
<property name= "checkouttimeout" value= "${c3p0.checkouttimeout}" />
<property name= "acquireretryattempts" value= "${c3p0.acquireretryattempts}" />
</bean>
<!--配置sqlsessionfactory-->
<bean id= "sqlsessionfactory" class = "org.mybatis.spring.sqlsessionfactorybean" >
<property name= "datasource" ref= "datasource" />
<!--扫描model包,使用别名-->
<property name= "typealiasespackage" value= "com.kevin.hrsystem.model" />
<property name= "mapperlocations" value= "classpath:mapper/*.xml" />
</bean>
<!--配置扫描dao接口包,动态实现dao接口,注入到spring容器中-->
<bean class = "org.mybatis.spring.mapper.mapperscannerconfigurer" >
<property name= "sqlsessionfactorybeanname" value= "sqlsessionfactory" />
<property name= "basepackage" value= "com.kevin.hrsystem.dao" />
</bean>
<!--配置事务管理器-->
<bean id= "transactionmanager" class = "org.springframework.jdbc.datasource.datasourcetransactionmanager" >
<!--注入数据库连接池-->
<property name= "datasource" ref= "datasource" />
</bean>
<tx:annotation-driven transaction-manager= "transactionmanager" />
</beans>
|
根据上面的配置文件可以看出,我们的dao层实现类是放在了classpath:mapper路径下面的,这里我们一样只给出employeedao组件的实现,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
<?xml version= "1.0" encoding= "utf-8" ?>
<!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace= "com.kevin.hrsystem.dao.employeedao" >
<insert id= "save" parametertype= "employee" usegeneratedkeys= "true" keyproperty= "id" >
insert into employee_inf(emp_type, emp_name, emp_pass, emp_salary, mgr_id, dept_name) values (#{type}, #{name}, #{password}, #{salary}, #{manager.id}, #{departmentname})
</insert>
<insert id= "saveasemployee" parametertype= "employee" usegeneratedkeys= "true" keyproperty= "id" >
insert into employee_inf(emp_type, emp_name, emp_pass, emp_salary, mgr_id) values (#{type}, #{name}, #{password}, #{salary}, #{manager.id})
</insert>
<insert id= "saveasmanager" parametertype= "manager" usegeneratedkeys= "true" keyproperty= "id" >
insert into employee_inf(emp_type, emp_name, emp_pass, emp_salary, dept_name) values (#{type}, #{name}, #{password}, #{salary}, #{departmentname})
</insert>
<delete id= "delete" parametertype= "long" >
delete from employee_inf where emp_id=#{id}
</delete>
<update id= "update" parametertype= "employee" >
update employee_inf set emp_name=#{name}, emp_pass=#{password}, emp_salary=#{saraly}, emp_type=#{type}, mgr_id=#{manager.id} where emp_id=#{id}
</update>
<!--查询语句 start-->
<select id= "findall" resultmap= "employeeresultmap" >
select * from employee_inf
</select>
<select id= "findbyid" parametertype= "long" resultmap= "employeeresultmap" >
select * from employee_inf where emp_id=#{id}
</select>
<select id= "findbynameandpass" resultmap= "employeeresultmap" >
select * from employee_inf where emp_name=#{name} and emp_pass=#{password}
</select>
<select id= "findbyname" resultmap= "employeeresultmap" >
select * from employee_inf where emp_name=#{name}
</select>
<!--根据mgr_id查找员工-->
<select id= "findemployeesbymgrid" parametertype= "long" resultmap= "employeeresultmap" >
select * from employee_inf where mgr_id=#{id}
</select>
<!--查询语句 end -->
<!-- resultmap设置,使用鉴别器来区分employee和manager-->
<resultmap id = "employeeresultmap" type= "com.kevin.hrsystem.model.employee" >
<id property= "id" column= "emp_id" />
<result property= "type" column= "emp_type" />
<result property= "name" column= "emp_name" />
<result property= "password" column= "emp_pass" />
<result property= "salary" column= "emp_salary" />
<discriminator javatype= "int" column= "emp_type" >
< case value= "1" resultmap= "originalemployeeresultmap" />
< case value= "2" resultmap= "managerresultmap" />
</discriminator>
</resultmap>
<resultmap id= "originalemployeeresultmap" type= "com.kevin.hrsystem.model.employee" extends = "employeeresultmap" >
<association property= "manager" javatype= "com.kevin.hrsystem.model.manager" >
<id property= "id" column= "mgr_id" />
</association>
</resultmap>
<resultmap id= "managerresultmap" type= "com.kevin.hrsystem.model.manager" extends = "employeeresultmap" >
<result property= "departmentname" column= "dept_name" />
<collection property= "employees" column= "emp_id" oftype= "com.kevin.hrsystem.model.employee" select= "com.kevin.hrsystem.dao.employeedao.findemployeesbymgrid" />
</resultmap>
<!--基础resultmap end-->
<select id= "selectbyidwithforeign" parametertype= "long" resultmap= "employeewithforeignresultmap" >
select e.emp_id, e.emp_name, e.emp_pass, e.emp_type, e.emp_salary, m.emp_id mgr_id, m.emp_name mgr_name, m.dept_name from employee_inf e, employee_inf m where e.mgr_id = m.emp_id and e.emp_id = #{id}
</select>
<resultmap id = "employeewithforeignresultmap" type= "com.kevin.hrsystem.model.employee" >
<id property= "id" column= "emp_id" />
<result property= "type" column= "emp_type" />
<result property= "name" column= "emp_name" />
<result property= "password" column= "emp_pass" />
<result property= "salary" column= "emp_salary" />
<association property= "manager" javatype= "com.kevin.hrsystem.model.manager" >
<id property= "id" column= "mgr_id" />
<result property= "name" column= "mgr_name" />
<result property= "departmentname" column= "dept_name" />
</association>
</resultmap>
</mapper>
|
这个xml文件就是我们employeedao组件的实现类了。关于这个类的鉴别器使用可以参考ssm项目问题与解决(还没有出)
四,service层
1)业务逻辑组件的设计
业务逻辑组件是dao组件的门面,所以可以理解为业务逻辑组件需要依赖于dao组件。empmanagerservice接口(业务逻辑组件之一)里定义了大量的业务方法,这些方法的实现依赖于dao组件,由于每个业务都要涉及多个dao操作,其dao操作是单条数据记录的操作,而业务逻辑方法的访问,则需要设计多个dao操作,因此每个业务逻辑方法可能需要涉及多条记录的访问
业务逻辑组件面向dao接口编程,可以让业务逻辑组件从dao组件的实现中分离,因此业务逻辑组件只关系业务逻辑的实现,无须关心数据访问逻辑的实现
empmanagerservice接口的代码实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
package com.kevin.hrsystem.service;
import com.kevin.hrsystem.model.attendtype;
import com.kevin.hrsystem.model.employee;
import com.kevin.hrsystem.model.manager;
import com.kevin.hrsystem.vo.attendvo;
import com.kevin.hrsystem.vo.paymentvo;
import java.util.list;
public interface empmanagerservice {
/**
* 验证登录
* @param employee 登录的身份
* @return
* 登录后的身份确认:0为登录失败,1为登录emp,2为登录mgr
*/
int validlogin(employee employee);
/**
* 自动打卡,周一到周五,早上7点为每个员工插入旷工记录
*/
void autopunch();
/**
* 自动结算工资,每月1号,结算上个月工资
*/
void autopay();
/**
* 验证某个员工是否可以打卡,以及打卡的类型,上班打卡,还是下班打卡
* @param user 员工名
* @param dutyday 日期
* @return 可打卡的类别
*/
int validpunch(string user, string dutyday);
/**
* 实现普通员工的打卡
* @param user 员工名
* @param dutyday 打卡日期
* @param iscome 是否是上班打卡
* @return 打卡结果
*/
int punch(string user, string dutyday, boolean iscome);
/**
* 根据员工浏览自己的工资
* @param employeename 员工名
* @return 该员工的工资列表
*/
list<paymentvo> employeesalary(string employeename);
/**
* 员工查看自己的最近三天的非正常打卡
* @param employeename 员工名
* @return 该员工最近三天的非正常打卡
*/
list<attendvo> getunattend(string employeename);
/**
* 返回全部的出勤类别
* @return 全部的出勤类别
*/
list<attendtype> getalltype();
/**
* 添加申请
* @param attid 申请的出勤id
* @param typeid 申请的类型id
* @param reason 申请的理由
* @return 添加的结果
*/
boolean addapplication( int attid, int typeid, string reason);
}
|
2)实现业务逻辑组件
业务逻辑组件负责实现系统所需的业务方法,系统有多少个业务需求,业务逻辑组件就提供多少个对应方法,本应用采用的贫血模式的架构模型,因此业务逻辑方法完全由业务逻辑组件负责实现。
业务逻辑组件只负责业务逻辑上的变化,而持久层的变化则交给dao层负责,因此业务逻辑组件必须依赖于dao组件。
下面是empmanagerserviceimpl的代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|