Java Web 开发进阶案例之人事管理系统的完整实现
概述
详细
一、概述
本系统的主要任务是实现人事管理系统的系统化和自动化管理, 主要包括招聘入
职、到期离职和员工调动信息管理等功能。具体完成的功能如下:
员工信息管理:员工信息查询、员工入职登记,员工信息更改、删除等
员工调动管理:员工调动登记、员工调动记录查询,员工调动信息更改、删除等
银行账户管理:
公司银行账户管理:公司银行账户登记和公司银行账户信息更改。
员工银行账户管理:员工银行账户登记、员工银行账户更改和删除等
公司信息管理:
职位类别管理:职位类别添加、职位类别信息更改、删除等
部门信息管理:部门类别添加、部门信息更改、删除等
系统管理:
登录密码修改模块
管理员管理模块:管理员添加、管理员信息更改和管理员删除等
系统帮助:关于使用该系统的一些帮助文档信息。
二、 开发平台与环境
本系统是 基于 B/S 平台的系统,利用 jsp + servlet+ javabeans 技术,基于 MVC 三层模式,
开发工具使用 MyEclipse 8.5 集成开发环境,数据库管理工具 SQL Server 2005 等。
三、系统的分析、设计与实现
1 系统分析:
(1) 角色分析:由于该系统属于典型的 MIS 管理系统,系统主要使用对象是管理员,分
为两类普通管理员和系统管理员;普通管理员只具有一般的查看、查询和检索权限;
系统管理员除了普通管理员所具有的权限外,还有高级权限:对所有信息做出更改,
删除等权限功能。
(2) 用例分析:根据用例分析所得到如下系统用例图:
2 系统设计:
2.1 数据库设计:
根据系统的分析与设计,如下设计数据库的数据表和数据结构:
2.1.1 逻辑表设计:
管理员表: id,登录名,登录密码,管理员类型号
管理员类型表: id,管理员类型号,管理员类型
员工基本信息表: id,员工编号,姓名,性别,出生日期,职位,部门,工资,入职时
间,身份证号
职位类别表: id,岗位编号,岗位名称,岗位工资
部门信息表: id,部门编号,部门名称,部门职能,部门领导
职位设置表: id,部门编号,岗位编号)
员工调动表: id,职工编号,原职位,调任职位,原部门编号,调任部门编号,性质,备
注
公司基本信息表: id,公司名称,公司性质,法人代表,公司地址,电话,邮箱:
公司银行账户表: id,银行账号,银行账户类型,开户行,备注:
员工银行账户表: id,员工编号,银行账号,银行账户,开户行,备注:
2.1.2 数据字典设计:
数据字典:
管理员表(admins)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
aName | Nvarchar(20) | 管理员登录名 |
aPwd | Nvarchar(20) | 管理员登陆密码 |
aTypeId | Int | 管理员类型号 |
管理员类型表(admintype)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
aTypeId | Nvarchar(20) | 管理员类型 |
aTypeName | Nvarchar(20) | 管理员类型名称 |
员工基本信息表(staff)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
sId | Nvarchar(14) | 员工编号 |
sName | Nvarchar(20) | 员工姓名 |
sSex | Nvarchar(2) | 员工性别 |
sBirthday | Datetime | 出生日期 |
sPost | Nvarchar(20) | 职位,岗位 |
sDepartment | Nvarchar(20) | 部门 |
sSalary | Int | 工资 |
sEntry | Datetime | 入职时间 |
sIdentityId | Nvarchar(20) | 身份证号 |
职位类别表(postcategory)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
pId | Nvarchar(20) | 职位编号 |
pName | Nvarchar(20) | 职位名称 |
pSalary | int | 职位工资 |
部门信息表(department)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
dId | Nvarchar(20) | 部门编号 |
dName | Nvarchar(20) | 部门名称 |
dFunction | Text | 部门职能 |
dLeader | Nvarchar(20) | 部门领导(经理) |
职位设置表(postsetting)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
pId | Nvarchar(20) | 职位编号 |
dId | Nvarchar(20) | 部门编号 |
员工调动表(staffchange)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
sId | Nvarchar(10) | 员工编号 |
pIdOld | Nvarchar(20) | 原职位编号 |
pIdNew | Nvarchar(20) | 调任职位编号 |
dIdOld | Nvarchar(20) | 原部门编号 |
dIdNew | Nvarchar(20) | 调任部门编号 |
sNature | Nvarchar(20) | 性质(长期或短期) |
sRemark | Text | 备注 |
公司基本信息表(company)
字段 | 类型 | 备注 |
id | Int | 主键 |
cName | Nvarchar(50) | 公司名称 |
cNature | Nvarchar(20) | 公司性质 |
cLegalPerson | Nvarchar(20) | 法人代表 |
cAddress | Nvarchar(100) | 公司地址 |
cTel | Nvarchar(20) | 电话 |
cEmail | Nvarchar(40) | 邮箱 |
公司银行账户表(companybank)
字段 | 类型 | 备注 |
id | Int | 主键 |
bId | Nvarchar(30) | 银行账号 |
cBankType | Nvarchar(20) | 银行账户类型 |
cBankName | Nvarchar(60) | 开户行 |
cRemark | Text | 备注 |
员工银行账户表(staffbank)
字段 | 类型 | 备注 |
id | Int | 主键,自增 |
sId | Nvarchar(20) | 员工编号 |
bId | Nvarchar(30) | 银行账号 |
cBankType | Nvarchar(20) | 银行账户类型 |
cBankName | Nvarchar(60) | 开户行 |
cRemark | Text | 备注 |
2.2 系统设计思想
(1)系统界面设计
由于该系统是个典型的 MIS 管理系统,本系统采用框架页面设计模式。常用
的头部和尾巴设计成单独模块,提高开发效率,提高模块重用性,方便系统升级。
(2)系统架构模式
本系统采用的是基于 Web 的 Java EE MVC 三层架构模式。
三层架构模式的原理图如下:
而将 MVC 三层模式应用于 Java EE 中,就是基于 JSP+Servlet+javabeans,其中, JSP 是视图,
servlet 是控制器,而 javabeans 则是模型。原理图如下:
3 系统实现:
(1)公用模块:
Commons Dbutils jar 包:该包是 apache 开发的一个用来常用操作的工具包。
字节编码过滤功能:该模块是使用过滤器技术对所有 servlet 编码设置进行过滤,主要用来解
决 jsp 中汉字问题。核心代码如下:
public class CharacterEncodingFilter implements Filter { private FilterConfig config ; private String encoding="ISO-8859-1"; public void destroy() { // TODO Auto-generated method stub config = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub request.setCharacterEncoding(encoding); chain.doFilter(request, response); } public void init(FilterConfig config) throws ServletException { // TODO Auto-generated method stub this.config = config; String s = config.getInitParameter("encoding"); if(s!=null){ encoding = s; } } }
Tomcat 数据库连接池技术:本系统采用 tomcat 数据池技术,便于数据库的配置和访问。 具
体配置是在 tomcat 安装目录下的 conf 文件下的 context.xml 文件中添加如下代码:
<Resource name="jdbc/permanageds" auth="Container" type="javax.sql.DataSource" maxActive = "100" maxIdle="30" maxWait="10000" username="sa" password="caizhiming" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://localhost:1433;DatabaseName=permanage" />
SQL 数据库操作工具类:该类主要用来处理与数据库相关的操作,核心代码如下:
public class SqlDbUtil { private String dataSourceName; private DataSource ds; public SqlDbUtil() { // TODO Auto-generated constructor stub } public SqlDbUtil(String dataSourceName){ this.dataSourceName = dataSourceName; } public void setDataSourceName(String dataSourceName) { this.dataSourceName = dataSourceName; } public void setDs(DataSource ds) { this.ds = ds; } //初始化数据源 public void init(){ try { Context initContext = new InitialContext(); this.ds = (DataSource)initContext.lookup(dataSourceName); initContext.close(); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //更新数据库语句,结果返回int类型 public int update(String sql,String[] params){ QueryRunner qr = new QueryRunner(ds); int result = 0; try { if(params!=null) result = qr.update(sql, params); else { result = qr.update(sql); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } //更新数据库语句,结果返回为Object类型,创建javabeans类型时用 public Object query(String sql,String[] params,ResultSetHandler rsh){ QueryRunner qr = new QueryRunner(ds); Object results = null; try { results=qr.query(sql, params, rsh); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return results; } }
字符串工具类: 该类主要用类处理一些字符串相关操作等所用到的工具方法,相关核心代码
如下:
public class StringUtil { //验证字符串是否为空 public static boolean validateNull(String s){ if(s==null || s.length()==0) return true; else { return false; } } //改变空字符串 public static String changeNull(String source,String target){ if(source==null || source.length()==0 || source.equalsIgnoreCase("null")) return target; else { return source; } } //过滤 html标记符 public static String filterHtml(String s){ if(s==null) return null; if(s.length()==0) return s; s.replaceAll("&", "&"); s.replaceAll("<", "<"); s.replaceAll(">", ">"); s.replaceAll(" ", " "); s.replaceAll("'", "';"); s.replaceAll("\"", """); s.replaceAll("\n", "<br/>"); return s; } }
(2) 系统登录模块实现: 该模块是系统的使用入口,通过该入口进入系统。 登录验证采用
Session 验证机制。
核心代码如下:
String path =request.getContextPath(); request.setCharacterEncoding("utf-8"); int typeId = 1; String name = request.getParameter("name").trim(); String pwd = request.getParameter("pwd"); String type = request.getParameter("type"); if(type.equalsIgnoreCase("普通管理员")) typeId = 0; String strCmd ="select * from admins where aName='"+name+"' and aPwd='"+pwd+"' and aTypeId='"+typeId+"' "; SqlDbUtil dbUtil = new SqlDbUtil("java:/comp/env/jdbc/permanageds"); dbUtil.init(); List list = (List)dbUtil.query(strCmd, null, new BeanListHandler(Admins.class)); if(list.size()!=0){ HttpSession session = request.getSession(); Admins ad = (Admins)list.get(0); session.setAttribute("aId", ad.getId()); session.setAttribute("name", name); session.setAttribute("type", type); response.sendRedirect(path+"/index.jsp"); } else { response.sendRedirect(path+"/login.jsp"); request.setAttribute("msg", "用户名或密码错误,请重新登录!"); }
登录界面如下:
(3) 员工信息管理模块实现
该模块主要有员工信息查询、入职登记以及修改删除等。
员工信息查询主要是通过搜索检索查询员工的信息,查询结果分页形式显示出来,
具体核心代码如下:
String text = "%"+request.getParameter("search").trim()+"%"; String type = request.getParameter("type").trim(); SqlDbUtil dbUtil = new SqlDbUtil("java:/comp/env/jdbc/permanageds"); dbUtil.init(); //每页显示记录数 int PageSize =8; int StartRow = 0; //开始显示记录的编号 int PageNo = 0;//需要显示的页数 int CounterStart = 0;//每页页码的初始值 int CounterEnd = 0;//显示页码的最大值 int RecordCount = 0;//总记录数; int MaxPage = 0;//总页数 int PrevStart = 0;//前一页 int NextPage = 0;//下一页 int LastRec = 0; //int LastStartRecord = 0;//最后一页开始显示记录的编号 //获取需要显示的页数,由用户提交 if (request.getParameter("page") == null) { //如果为空,则表示第1 页 if (StartRow == 0) { PageNo = StartRow + 1; //设定为1 } } else { PageNo = Integer.parseInt(request.getParameter("page")); // 获得用户提交的页数 StartRow = (PageNo - 1) * PageSize; //获得开始显示的记录编号 } //因为显示页码的数量是动态变化的,假如总共有一百页,则不可能同时显示100个链 接。而是根据当前的页数显示 //一定数量的页面链接 //设置显示页码的初始值!! if (PageNo % PageSize == 0) { CounterStart = PageNo - (PageSize - 1); } else { CounterStart = PageNo - (PageNo % PageSize) + 1; } CounterEnd = CounterStart + (PageSize - 1); String strSql1 = null; if(type.equals("sId")) strSql1 = "select * from staff where sId like '"+text+"'"; if(type.equals("sName")) strSql1 = "select * from staff where sName like '" +text+ "'"; if(text.isEmpty()) strSql1 = "select * from staff "; List list = (List) dbUtil.query(strSql1, null, new BeanListHandler(Staff.class)); RecordCount = list.size(); //取特定页数的数据 String strColumn = " * "; String strTable = " staff "; String strSort = " id desc "; String PKID = "id"; String strSql2 = ""; String strWhere = "where " + type +" like "+ "'"+text+"'" ; String START_ID = Integer.toString((PageNo - 1) * PageSize + 1); String END_ID = Integer.toString(PageNo * PageSize); strSql2 = " SELECT " + strColumn + " FROM (SELECT ROW_NUMBER() OVER(ORDER BY " + strSort + ") AS rownum," + strColumn + " FROM " + strTable + " WITH(NOLOCK) " + strWhere + ") AS D WHERE rownum BETWEEN " + START_ID + " AND " + END_ID + " ORDER BY " + strSort; //获取总页数 MaxPage = RecordCount % PageSize; if (RecordCount % PageSize == 0) { MaxPage = RecordCount / PageSize; } else { MaxPage = RecordCount / PageSize + 1; } List list2 = (List) dbUtil.query(strSql2, null, new BeanListHandler(Staff.class)); request.setAttribute("staff", list2); request.setAttribute("PageSize", PageSize); request.setAttribute("StartRow", StartRow); request.setAttribute("PageNo", PageNo); request.setAttribute("CounterStart", CounterStart); request.setAttribute("CounterEnd", CounterEnd); request.setAttribute("RecordCount", RecordCount); request.setAttribute("MaxPage", MaxPage); request.setAttribute("PrevStart", PrevStart); request.setAttribute("NextPage", NextPage); request.setAttribute("LastRec", LastRec); request.getRequestDispatcher("/staff/staffsearch.jsp").forward(re quest, response);
系统主界面如下:
入职登记是登记新入职员工信息,具体核心代码如下:
String path = request.getContextPath(); int result = 0; String sId = null; String sName = request.getParameter("sName").trim(); String sSex = request.getParameter("sSex").trim(); String birth=request.getParameter("birthyear")+"-"+request.getParameter("bir thmon"); birth+="-"+request.getParameter("birthday"); String job = request.getParameter("jobyear")+"-"+request.getParameter("jobmon"); job += "-"+request.getParameter("jobday"); Date birthDate =null; Date jobDate = null; Date sIdDate=null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat sdf2=new SimpleDateFormat("yyyyMMddHHmmss"); try { birthDate = sdf.parse(birth); jobDate = sdf.parse(job); sId = sdf2.format(new java.util.Date()); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } String pId = request.getParameter("sPost").trim();// 获取的是职位 对应的职位编号 String sSalary = request.getParameter("sSalary").trim(); String sIdentityId = request.getParameter("sIdentityId").trim(); SqlDbUtil db = new SqlDbUtil("java:/comp/env/jdbc/permanageds"); db.init(); String strCmd2 = "select * from postsetting where pId ='" + pId + "'"; List list2 = (List) db.query(strCmd2, null, new BeanListHandler(Postsetting.class)); Postsetting ps = (Postsetting) list2.get(0); String dId = ps.getdId(); String strCmd4 = "select * from postcategory where pId ='" + pId + "'"; List list4 = (List) db.query(strCmd4, null, new BeanListHandler(Postcategory.class)); Postcategory pc = (Postcategory) list4.get(0); String sPost =pc.getpName(); String strCmd3 = "select * from department where dId ='" + dId + "'"; List list3 = (List) db.query(strCmd3, null, new BeanListHandler(Department.class)); Department dt = (Department) list3.get(0); String sDepartment = dt.getdName();// 获取到职位所隶属的部门名称 String strCmd = "insert into staff (sId,sName,sSex,sBirthday,sPost,sDepartment,sSalary,sEntry,sIdentityI d) values(?,?,?,?,?,?,?,?,?)"; String[] params = { sId, sName, sSex, sdf.format(birthDate), sPost,sDepartment, sSalary, sdf.format(jobDate), sIdentityId }; for(int i=0;i<100000;i++){ result = db.update(strCmd, params); } if (result == 0) { String message = "对不起,内容更新失败,请重新更新! <br/>"; request.getRequestDispatcher("/company/addpostcategory.jsp") .forward(request, response); } else { response.sendRedirect(path + "/servlet/manageStaff"); }
员工信息管理主要是负责员工信息的修改和删除功能。
信息修改的核心代码如下:
String path = request.getContextPath(); int result = 0; request.setCharacterEncoding("utf-8"); String sName = request.getParameter("sName").trim(); String sSex = request.getParameter("sSex").trim(); String birth=request.getParameter("birthyear")+"-"+request.getParameter("bir thmon"); birth+="-"+request.getParameter("birthday"); String job = request.getParameter("jobyear")+"-"+request.getParameter("jobmon"); job += "-"+request.getParameter("jobday"); Date birthDate =null; Date jobDate = null; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { try { birthDate = sdf.parse(birth); jobDate = sdf.parse(job); } catch (java.text.ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } String sId = request.getParameter("sId").trim(); String pId = request.getParameter("sPost").trim();// 获取的是职位 对应的职位编号 String sSalary = request.getParameter("sSalary").trim(); String sIdentityId = request.getParameter("sIdentityId").trim(); SqlDbUtil db = new SqlDbUtil("java:/comp/env/jdbc/permanageds"); db.init(); String strCmd2 = "select * from postsetting where pId ='" + pId + "'"; List list2 = (List) db.query(strCmd2, null, new BeanListHandler(Postsetting.class)); Postsetting ps = (Postsetting) list2.get(0); String dId = ps.getdId(); String strCmd4 = "select * from postcategory where pId ='" + pId + "'"; List list4 = (List) db.query(strCmd4, null, new BeanListHandler(Postcategory.class)); Postcategory pc = (Postcategory) list4.get(0); String sPost =pc.getpName(); String strCmd3 = "select * from department where dId ='" + dId + "'"; List list3 = (List) db.query(strCmd3, null, new BeanListHandler(Department.class)); Department dt = (Department) list3.get(0); String sDepartment = dt.getdName();// 获取到职位所隶属的部门名称 String strCmd="update staff set sName=?, sSex=?, sBirthday=?, sPost=?, sDepartment=?, sSalary=?, sEntry=?, sIdentityId=? where sId='"+sId+"'"; String[] params = { sName, sSex, sdf.format(birthDate), sPost,sDepartment, sSalary, sdf.format(jobDate), sIdentityId }; result = db.update(strCmd, params); if (result == 0) { String message = "对不起,内容更新失败,请重新更新! <br/>"; request.getRequestDispatcher("/staff/addstaff.jsp") .forward(request, response); } else { response.sendRedirect(path + "/servlet/manageStaff"); //request.getRequestDispatcher("/servlet/manageStaff").forward(re quest, response); }
删除功能的核心代码如下:
String path = request.getContextPath(); int result = 0; request.setCharacterEncoding("utf-8"); String sId = request.getParameter("sId").toString(); //String strCmd = "delete from where id='"+id+"'"; String strCmd = "delete from staff where sId='"+sId+"'"; SqlDbUtil dbUtil = new SqlDbUtil("java:/comp/env/jdbc/permanageds"); dbUtil.init(); result = dbUtil.update(strCmd, null); if(result > 0) response.sendRedirect(path+"/servlet/manageStaff");
(4) 员工调动信息管理模块实现
该模块主要是实现员工调动信息的管理,主要包括员工调动信息登记,更改和删除,
相关核心代码与员工信息管理类似,详见源代码。 实现界面如下:
(5) 银行账户信息模块实现
该模块主要是实现公司银行和员工工资账户的管理,主要包括公司银行账户的创建、
查看和修改以及员工工资账户的登记、修改和删除等功能,相关核心代码与员工信
息管理类似, 在此不累赘, 详见源代码。 实现界面如下:
(6) 公司信息管理模块实现
该模块主要是实现公司相关信息的管理,主要包括公司基本信息的查看和更新、公
司部门信息管理以及公司职位类别管理, 该模块的相关核心代码实现与员工信息管
理类似, 在此不累赘, 详见源代码。
(7) 系统管理模块实现
该模块主要是实现系统管理员的管理,主要包括管理员添加、更新和删除等功能,
相关核心代码与上面的类似,在此不累赘,详见源代码。 实现界面如下:
四、项目代码目录结构图