开发多级审批流程

请假流程

设计约束

每一个请假单对应一个审批流程。
请假单创建后,按业务规则生成部门经理、总经理审批任务。
审批任务的经办人只能审批自己辖区内的请假申请。
所有审批任务“通过”,代表请假已经批准。
任意审批任务“驳回”操作,其余审批任务取消,请假申请驳回。
请假流程中的任意节点产生的操作都要生成对应的系统通知。

工作流程表设计


打开navicat,创建adm_leave_form请假单表

创建adm_process_flow审批任务流程表

创建sys_notice消息通知表

实现Dao与数据交互

先将实体类创建好

package com.ql.oa.entity;import java.util.Date;public class LeaveForm {private Long formId;private Long employeeId;private Integer formType;private Date startTime;private Date endTime;private String reason;private Date createTime;private String state;public Long getFormId() {return formId;}public void setFormId(Long formId) {this.formId = formId;}public Long getEmployeeId() {return employeeId;}public void setEmployeeId(Long employeeId) {this.employeeId = employeeId;}public Integer getFormType() {return formType;}public void setFormType(Integer formType) {this.formType = formType;}public Date getStartTime() {return startTime;}public void setStartTime(Date startTime) {this.startTime = startTime;}public Date getEndTime() {return endTime;}public void setEndTime(Date endTime) {this.endTime = endTime;}public String getReason() {return reason;}public void setReason(String reason) {this.reason = reason;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public String getState() {return state;}public void setState(String state) {this.state = state;}
}
package com.ql.oa.entity;import java.util.Date;public class ProcessFlow {private Long processId;private Long formId;private Long operatorId;private String action;private String result;private String reason;private Date createTime;private Date auditTime;private Integer orderNo;private String state;private Integer isLast;public Long getProcessId() {return processId;}public void setProcessId(Long processId) {this.processId = processId;}public Long getFormId() {return formId;}public void setFormId(Long formId) {this.formId = formId;}public Long getOperatorId() {return operatorId;}public void setOperatorId(Long operatorId) {this.operatorId = operatorId;}public String getAction() {return action;}public void setAction(String action) {this.action = action;}public String getResult() {return result;}public void setResult(String result) {this.result = result;}public String getReason() {return reason;}public void setReason(String reason) {this.reason = reason;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Date getAuditTime() {return auditTime;}public void setAuditTime(Date auditTime) {this.auditTime = auditTime;}public Integer getOrderNo() {return orderNo;}public void setOrderNo(Integer orderNo) {this.orderNo = orderNo;}public String getState() {return state;}public void setState(String state) {this.state = state;}public Integer getIsLast() {return isLast;}public void setIsLast(Integer isLast) {this.isLast = isLast;}
}
package com.ql.oa.entity;import java.util.Date;public class Notice {private Long noticeId;private Long receiverId;private String content;private Date createTime;public Notice(){}public Notice(Long receiverId , String content){this.receiverId = receiverId;this.content = content;this.createTime = new Date();}public Long getNoticeId() {return noticeId;}public void setNoticeId(Long noticeId) {this.noticeId = noticeId;}public Long getReceiverId() {return receiverId;}public void setReceiverId(Long receiverId) {this.receiverId = receiverId;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}
}

然后把每个实体类的数据交互的接口Dao创建好并填写新增数据的方法:

package com.ql.oa.dao;import com.ql.oa.entity.LeaveForm;public interface LeaveFormDao {public void insert(LeaveForm form);
}
package com.ql.oa.dao;import com.ql.oa.entity.ProcessFlow;public interface ProcessFlowDao {public void insert(ProcessFlow processFlow);
}
package com.ql.oa.dao;import com.ql.oa.entity.Notice;public interface NoticeDao {public void insert(Notice notice);
}

然后在resources\mappers下创建mapper文件并在mybatis-config.xml里配置

<?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.ql.oa.dao.LeaveFormDao"><insert id="insert" parameterType="com.ql.oa.entity.LeaveForm"useGeneratedKeys="true" keyProperty="formId" keyColumn="form_id">INSERT INTO adm_leave_form( employee_id, form_type, start_time, end_time, reason, create_time, state)VALUES ( #{employeeId}, #{formType}, #{startTime}, #{endTime}, #{reason}, #{createTime}, #{state})</insert>
</mapper>
<?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.ql.oa.dao.ProcessFlowDao"><insert id="insert" parameterType="com.ql.oa.entity.ProcessFlow"useGeneratedKeys="true" keyColumn="process_id" keyProperty="processId">INSERT INTO adm_process_flow(form_id, operator_id, action, result, reason, create_time , audit_time , order_no , state,is_last)VALUES (#{formId}, #{operatorId}, #{action}, #{result}, #{reason}, #{createTime} , #{auditTime} , #{orderNo} , #{state} , #{isLast});</insert>
</mapper>
<?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.ql.oa.dao.NoticeDao"><insert id="insert" parameterType="com.ql.oa.entity.Notice"useGeneratedKeys="true" keyProperty="noticeId" keyColumn="notice_id">INSERT INTO sys_notice( receiver_id, content, create_time) VALUES (#{receiverId}, #{content}, #{createTime})</insert>
</mapper>
    <mappers><mapper resource="mappers/user.xml"/><mapper resource="mappers/rbac.xml"/><mapper resource="mappers/employee.xml"/><mapper resource="mappers/department.xml"/><mapper resource="mappers/leave_form.xml"/><mapper resource="mappers/process_flow.xml"/><mapper resource="mappers/notice.xml"/></mappers>

开发请假申请功能

在EmployeeDao接口中新增一个方法,并且在相应的employee.xml中添加实现:

    /*** 根据传入员工对象获取上级主管对象* @param employee 员工对象* @return 上级主管对象*/public Employee selectLeader(@Param("emp") Employee employee);
    <select id="selectLeader" parameterType="com.ql.oa.entity.Employee" resultType="com.ql.oa.entity.Employee">select * from adm_employeewhere<if test="emp.level &lt; 7">level = 7 and department_id = #{emp.departmentId}</if><if test="emp.level == 7">level = 8</if><if test="emp.level == 8">employee_id = #{emp.employeeId}</if></select>

在com.ql.oa.service包下创建LeaveFormService.java请假单流程业务类,并编写创建请假单的方法

/*** 请假单流程服务*/
public class LeaveFormService {/*** 创建请假单* @param form 前端输入的请假单数据* @return 持久化后的请假单对象*/public LeaveForm createLeaveForm(LeaveForm form){LeaveForm savedForm = (LeaveForm)MyBatisUtils.executeUpdate(sqlSession -> {//1.持久化form表单数据,8级以下员工表单状态为processing,8级(总经理)状态为approvedEmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);Employee employee = employeeDao.selectById(form.getEmployeeId());if(employee.getLevel() == 8){form.setState("approved");}else{form.setState("processing");}LeaveFormDao leaveFormDao = sqlSession.getMapper(LeaveFormDao.class);leaveFormDao.insert(form);//2.增加第一条流程数据,说明表单已提交,状态为completeProcessFlowDao processFlowDao = sqlSession.getMapper(ProcessFlowDao.class);ProcessFlow flow1 = new ProcessFlow();flow1.setFormId(form.getFormId());flow1.setOperatorId(employee.getEmployeeId());flow1.setAction("apply");flow1.setCreateTime(new Date());flow1.setOrderNo(1);flow1.setState("complete");flow1.setIsLast(0);processFlowDao.insert(flow1);//3.分情况创建其余流程数据//3.1 7级以下员工,生成部门经理审批任务,请假时间大于72小时,还需生成总经理审批任务if(employee.getLevel() < 7){Employee dmanager = employeeDao.selectLeader(employee);ProcessFlow flow2 = new ProcessFlow();flow2.setFormId(form.getFormId());flow2.setOperatorId(dmanager.getEmployeeId());flow2.setAction("audit");flow2.setCreateTime(new Date());flow2.setOrderNo(2);flow2.setState("process");long diff = form.getEndTime().getTime() - form.getStartTime().getTime();float hours = diff/(1000*60*60) * 1f;if(hours >= BussinessConstants.MANAGER_AUDIT_HOURS){flow2.setIsLast(0);processFlowDao.insert(flow2);Employee manager = employeeDao.selectLeader(dmanager);ProcessFlow flow3 = new ProcessFlow();flow3.setFormId(form.getFormId());flow3.setOperatorId(manager.getEmployeeId());flow3.setAction("audit");flow3.setCreateTime(new Date());flow3.setState("ready");flow3.setOrderNo(3);flow3.setIsLast(1);processFlowDao.insert(flow3);}else {flow2.setIsLast(1);processFlowDao.insert(flow2);}}else if(employee.getLevel() == 7){ //部门经理//3.2 7级员工,生成总经理审批任务Employee manager = employeeDao.selectLeader(employee);ProcessFlow flow = new ProcessFlow();flow.setFormId(form.getFormId());flow.setOperatorId(manager.getEmployeeId());flow.setAction("audit");flow.setCreateTime(new Date());flow.setState("process");flow.setOrderNo(2);flow.setIsLast(1);processFlowDao.insert(flow);}else if(employee.getLevel() == 8){//3.3 8级员工,生成总经理审批任务,系统自动通过ProcessFlow flow = new ProcessFlow();flow.setFormId(form.getFormId());flow.setOperatorId(employee.getEmployeeId());flow.setAction("audit");flow.setResult("approved");flow.setReason("自动通过");flow.setCreateTime(new Date());flow.setAuditTime(new Date());flow.setState("complete");flow.setOrderNo(2);flow.setIsLast(1);processFlowDao.insert(flow);}return form;});return savedForm;}
}

然后在com.ql.oa.controller包下创建LeaveFormServlet并实现请假申请控制器:

@WebServlet(name = "LeaveFormServlet",urlPatterns = "/leave/*")
public class LeaveFormServlet extends HttpServlet {private LeaveFormService leaveFormService = new LeaveFormService();private Logger logger = LoggerFactory.getLogger(LeaveFormServlet.class);protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");// http://localhost/leave/createString uri = request.getRequestURI();String methodName = uri.substring(uri.lastIndexOf("/")+1);if(methodName.equals("create")){this.create(request,response);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request,response);}/*** 创建请假单* @param request* @param response* @throws ServletException* @throws IOException*/private void create(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 接收各项请假单数据HttpSession session = request.getSession();User user = (User)session.getAttribute("login_user");String formType = request.getParameter("formType");String strStartTime = request.getParameter("startTime");String strEndTime = request.getParameter("endTime");String reason = request.getParameter("reason");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH");Map result = new HashMap();try {LeaveForm form = new LeaveForm();form.setEmployeeId(user.getEmployeeId());form.setStartTime(sdf.parse(strStartTime));form.setEndTime(sdf.parse(strEndTime));form.setFormType(Integer.parseInt(formType));form.setReason(reason);form.setCreateTime(new Date());//2. 调用业务逻辑方法leaveFormService.createLeaveForm(form);result.put("code", "0");result.put("message", "success");} catch (Exception e) {logger.error("请假申请异常" ,e);result.put("code", e.getClass().getSimpleName());result.put("message", e.getMessage());}//3. 组织响应数据String json = JSON.toJSONString(result);response.getWriter().println(json);}
}

完整实现请假申请功能

在com.ql.oa.controller下新增ForwardServlet.java,实现页面跳转到对应的ftl文件

package com.ql.oa.controller;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 页面跳转Servlet*/
@WebServlet(name = "ForwardServlet" , urlPatterns = "/forward/*")
public class ForwardServlet extends HttpServlet {protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String uri = request.getRequestURI();/** /forward/form* /forward/a/b/c/form*/String subUri = uri.substring(1);String page = subUri.substring(subUri.indexOf("/"));request.getRequestDispatcher(page + ".ftl").forward(request,response);}
}

然后在webapp\resources路径下引入sweetalert2.all.min.js弹窗JS插件。

然后在src/main/webapp/WEB-INF/ftl下创建form.ftl请假表单申请页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>请假申请</title><link rel="stylesheet" href="/resources/layui/css/layui.css"><style>/*表单容器*/.ns-container {position: absolute;width: 500px;height: 450px;top: 150px;left: 50%;margin-left: -250px;padding: 20px;box-sizing: border-box;border: 1px solid #cccccc;}</style>
</head>
<body>
<div class="layui-row"><blockquote class="layui-elem-quote"><h2>请假申请</h2></blockquote><table id="grdNoticeList" lay-filter="grdNoticeList"></table>
</div>
<div class="ns-container"><h1 style="text-align: center;margin-bottom: 20px">请假申请单</h1><form class="layui-form"><!--基本信息--><div class="layui-form-item"><label class="layui-form-label">部门</label><div class="layui-input-block"><div class="layui-col-md12" style="padding-top: 10px;">${current_department.departmentName}</div></div></div><div class="layui-form-item"><label class="layui-form-label">申请人</label><div class="layui-input-block"><div class="layui-col-md12" style="padding-top: 10px;">${current_employee.name}[${current_employee.title}]</div></div></div><!--请假类型下拉框--><div class="layui-form-item"><label class="layui-form-label">请假类别</label><div class="layui-input-block layui-col-space5"><select name="formType" lay-verify="required" lay-filter="cityCode"><option value="1">事假</option><option value="2">病假</option><option value="3">工伤假</option><option value="4">婚嫁</option><option value="5">产假</option><option value="6">丧假</option></select></div></div><!--请假时长日期选择框--><div class="layui-form-item"><label class="layui-form-label">请假时长</label><div class="layui-input-block layui-col-space5"><input name="leaveRange" type="text" class="layui-input" id="daterange" placeholder=" - " autocomplete="off"><input id="startTime" name="startTime" type="hidden"><input id="endTime" name="endTime" type="hidden"></div></div><!--请假事由--><div class="layui-form-item"><label class="layui-form-label">请假事由</label><div class="layui-input-block layui-col-space5"><input name="reason" type="text"  lay-verify="required|mobile" placeholder="" autocomplete="off" class="layui-input"></div></div><!--提交按钮--><div class="layui-form-item " style="text-align: center"><button class="layui-btn" type="button" lay-submit lay-filter="sub">立即申请</button></div></form>
</div><script src="/resources/layui/layui.js"></script>
<!--Sweetalert2对话框-->
<script src="/resources/sweetalert2.all.min.js"></script><script>var layDate = layui.laydate; //Layui日期选择框JS对象var layForm = layui.form; //layui表单对象var $ = layui.$; //jQuery对象//日期时间范围layDate.render({elem: '#daterange',type: 'datetime',range: true,format: 'yyyy年M月d日H时',done: function(value, start, end){//选择日期后触发事件,设置startTime与endTime隐藏域var startTime = start.year + "-" + start.month + "-" + start.date + "-" + start.hours;var endTime = end.year + "-" + end.month + "-" + end.date + "-" + end.hours;console.info("请假开始时间",startTime);$("#startTime").val(startTime);console.info("请假结束时间",endTime);$("#endTime").val(endTime);}});//表单提交事件layForm.on('submit(sub)', function(data){console.info("向服务器提交的表单数据",data.field);$.post("/leave/create",data.field,function (json) {console.info("服务器返回数据",json);if(json.code == "0"){/*SweetAlert2确定对话框*/swal({type: 'success',html: "<h2>请假单已提交,等待上级审批</h2>",confirmButtonText: "确定"}).then(function (result) {window.location.href="/forward/notice";});}else{swal({type: 'warning',html: "<h2>" + json.message + "</h2>",confirmButtonText: "确定"});}},"json");return false;});</script>
</body>
</html>

然后打开navicat,打开sys_node表把菜单url填充,并打开index.ftl文件把菜单跳转路径改成动态的。

<!--子节点-->
<dd class="function" data-parent-id="${node.parentId}"><a href="${node.url}" target="ifmMain">${node.nodeName}</a>
</dd>

运行项目,登录后点击请假申请测试。

Java项目(一)--MyBatis实现OA系统项目实战(7)--开发多级审批流程相关推荐

  1. JAVA计算机毕业设计园林公司OA系统Mybatis+系统+数据库+调试部署

    JAVA计算机毕业设计园林公司OA系统Mybatis+系统+数据库+调试部署 JAVA计算机毕业设计园林公司OA系统Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

  2. 开源项目推荐-私人网盘系统项目

    开源项目推荐-私人网盘系统项目 参考网址: https://mp.weixin.qq.com/s/9QzQBAwf2f57PAuBZw6PXg 许多程序员都想搭建一个个人网盘,今天就和大家推荐一个备受 ...

  3. 电子政务源代码java_基于jsp的电子政务系统项目-JavaEE实现电子政务系统项目 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的电子政务系统项目, 该项目可用各类java课程设计大作业中, 电子政务系统项目的系统架构分为前后台两部分, 最终实 ...

  4. java开发oa系统的目的_JAVA开发的OA系统价值体现

    根据目前的OA市场,PHP和JAVA各自为政,PHP开发的OA产品主要是用于低价战,但JAVA开发的OA产品大部分集中在高价战.导致产品价格的关键因素:PHP门槛非常低,程序员数量也很多,再通过PHP ...

  5. 开源OA:手把手教你搭建OA办公系统(3)开发企业报销审批流程

    需求 今天以OA系统中的报销审批流程为例来讲一下流程应用管理.首先介绍一下报销流程的需求,主要分为两部分,流程和表单. 流程 OA的报销流程部分,我们将其分成两种情况:报销金额<=3000元时, ...

  6. OA系统二十四:请假审批五:【点击“审批”后的审批弹出框】的后台逻辑;(审批结果提交的Dao层和Service层逻辑)

    本篇博客的主要内容是:[请假审批内嵌页面],[审批弹出框]的点击"确认提交"后,后台的逻辑:主要是Dao层和Service层这些后台逻辑:  说明: (1)目前来看,为了实现某个功 ...

  7. OA系统如何实现严谨的费用报销流程

    在企业中,会遇到很多报销流程,例如:差旅费报销.日常办公费用.税费支出等等.多种复杂类型报销,领导很难在忙碌的状态下还能妥善管理资金流转,往往是力不从心.为此,很多企业开始利用管理软件来规范报销流程. ...

  8. 开源OA:手把手教你搭建OA办公系统(4)搭建报销审批流程

    O2OA拖曳式流程图开发 新建默认流程 首先我们修改流程名字为"报销审批流程",然后按照需求把所有的节点活动先拖过来,分别修改一下名字 接下来就要画上面的路由了,双击活动节点出现路 ...

  9. java多级审批流程_[SharePoint 工作流] 如何设计一个通用的多级多审核工作流程(三):工作流开发...

    在上2篇博客中,我们有了工作流定义的列表,也有了关联表单和启动表单,现在就是开始开发这个通用工作流的时刻了. 工作流的基本构成就是:一个While循环控制工作流的运转,While里的Task Repl ...

最新文章

  1. Struts2.3+Spring4.0
  2. Asp.net网站的ClickOnce自动部署(2)-虚拟目录的配置
  3. IE6-IE9兼容性问题列表及解决办法_补充之五:在IE9下, disabled的文本框内容被选中后,其他控件无法获得焦点问题...
  4. STM32一种基于NTC的控温电路及软件实现
  5. 自学Python6个月,找到了月薪8K的工作,多亏了这套学习方式
  6. java非侵入式接口实现,C++编写非侵入式接口
  7. VirusTotal 共享8000万勒索软件样本分析数据库
  8. [CSS3]Clearfix
  9. window下安装sonar
  10. php短信报警直到响应,Cacti实现短信报警
  11. Python,折线图,手写数字,图像反色、二值化、28X28
  12. 对于企业是云服务器划算还是自购服务器划算?
  13. 学习WEB前端第四天(3)-背景图像
  14. 作业周转时间以及平均等待时间
  15. 养成好习惯,戒掉坏习惯
  16. RabbitMQ原理名词解释
  17. 模板引擎ejs与html,后台模板引擎ejs与前台模板引擎artTemplate的简单介绍
  18. 计算机软件大赛征稿,全国多媒体教育软件大奖赛征稿函
  19. phpword html转word word转html
  20. rabbitmq消费者“无故消失”

热门文章

  1. redis 在java中的实例使用场景
  2. 字符串的定义与赋值及初始化
  3. jquery清空某个元素下的所有节点
  4. 浏览器首页被2345、hao123锁定了,怎么办
  5. python版本的判断、选择指南
  6. java split 双竖线_HIVE 常用函数及实例
  7. 泰森多边形(Voronoi图)生成算法
  8. 增加BUG的测试版本字段
  9. hdu 4544 湫湫系列故事——消灭兔子
  10. 使用hanewin实现 win系统主机,vm虚拟机中linux系统和开发板三方共享文件夹