造轮子系列之封装审批流程

业务中经常会遇见需要审批的环节,所以审批流应运而生,我自己封装了一个小的审批流,比较简单,跟一些开源框架没有啥可比性,所以有许多不严谨的地方。

审批流主要涉及3张表,前台jsp代码我就不提供了,只写一些后台的核心代码。审批流核心就是用户自己设置审批流程,如图1(这里涉及2张表,一张表为审批流程模板主表,第二张表为模板主表的明细),然后根据审批流程的明细,生成单据(比如项目审批,请假审批,文件审批等等)需要审批的所有流程(第三张表,单据审批流程)。

图1
这里写图片描述

先介绍3个bean,对应3个表
模板主表,ProcessTemplate.class。get、set方法省略。

public class ProcessTemplate{
    private int id;
    private String name;//审批流程模板名称
    private String number;//编号(唯一)
    private String createDate;//创建日期
    private String createdById;//创建人id
}

模板主表的明细,ProcessTemplateDtl.class。get、set方法省略。

public class ProcessTemplateDtl extends BaseInfoBean{
    public final static String ROLE = "01";//审核标识
    public final static String EMPLOYEE = "02";//审核标识
    public final static String FUN = "03";//审核标识

    private String name;//审批名称
    private Integer level;//审批等级,决定审批顺序
    private String auditSign;//审核标识    角色审核01  指定人审核02  回调函数 项目职务 03
    private Integer roleId;//角色id
    private String roleName;
    private Integer employeeId;//员工id
    private String employeeName;
    private String interfaceName;//接口名称
    private Integer templateId;//审批流程主表id
}

根据流程模板明细生成的单据审批流程。

public class AuditRecord extends BaseInfoBean{
    private Integer templateId;//模版id
    private Integer templateDtlId;//模板明细id
    private Integer lastId;//上一条记录id
    private String updateBillStatusIntf;//更新单据状态 接口名称 整个审批流程结束时调用 
    private String contentUrl;
    private String processUrl;
    private Integer level;//审批等级
    private Integer roleId;//角色id
    private String roleName;//角色名
    private Integer employeeId;//员工id
    private String employeeName;//员工名
    private String billName;//项目名
    private Integer billId;         //项目明细Id         
    private String billNumber;       //项目编码
    private String auditStatus;     //审核状态
    private String auditResult;     //审核结果
    private String auditComments;   //审核意见 
    private String badgePictureFile;//电子签名 
    private String batchNo;         //批号
    private Integer batchNum;       //批次
    private String processStatus;//审核不通过是 处理状态 在创建下一条审核记录时更新上一条记录为已审核 默认为空 ,审核不通过为0
    private String fileNames;//上传文件名
    private String filePaths;//上传文件路径
}

现在3个bean介绍完之后就开始按照图1,用户自定义完流程保存,我就写个save方法吧,增删改查我就不贴了。它还实现了接口ProcessTemplateIntf。

/**
*获得模版明细 
*/
public interface ProcessTemplateIntf {
    public List<ProcessTemplateDtl> getProcessTemplateDtl(Integer templateId);  
}
public class ProcessTemplateImpl extends BaseStaticImpl implements ProcessTemplateIntf {
    /**
     * 实现接口,获得模板明细
     */
    @Override
    public List<ProcessTemplateDtl> getProcessTemplateDtl(Integer templateId) {
        StringBuilder hql = new StringBuilder("select a from ProcessTemplateDtl as a where a.templateId = ").append(templateId);
        //其实就是根据主表id,把所有明细查询出来
        List lt = publicService.executeObjectSql(hql.toString());
        return lt;
    }
    /**
     * 保存审批模板主表和明细
     */
    @Override
    public boolean save(ActionForm form, Map parameterMap) {
        ProcessTemplateForm userForm = (ProcessTemplateForm)form;
        ProcessTemplate user = new ProcessTemplate();
        try{
            BeanUtils.copyProperties(user, userForm);
        }catch(Exception e){
            e.printStackTrace();
        }
        //获取流程主表的唯一number
        user.setNumber(getGenerateRuleIntf().generateNumber(user.getClass().getName()));
        //保存主表
        publicService.saveAutoIdObject(user);
        //表单提交上来,根据level来设几级审核
        for(int i=0;i<userForm.getLevel().length;i++){
            ProcessTemplateDtl dtl = new ProcessTemplateDtl();
            dtl.setLevel(userForm.getLevel()[i]);
            dtl.setName(userForm.getApprovalName()[i]);
            dtl.setAuditSign(userForm.getAuditSign()[i]);
            dtl.setEmployeeId(userForm.getEmployeeId()[i]);
            dtl.setEmployeeName(userForm.getEmployeeName()[i]);
            dtl.setRoleId(userForm.getRoleId()[i]);
            dtl.setRoleName(userForm.getRoleName()[i]);
            dtl.setInterfaceName(userForm.getInterfaceName()[i]);
            dtl.setTemplateId(user.getId());
            //保存 主表的明细表
            publicService.saveAutoIdObject(dtl);
        }
        return true;
    }
}

生成审批流的接口

public interface AuditProcessIntf {
    /**
     * 生成审批流
     * @param context
     * * billName 单据名称 
     * billNumber 单据编码 
     * updateBillStatusIntf 更新单据状态接口名称 
     * contentUrl 审核页面查看内容地址
     * processUrl 审核不通过时重新处理的页面 url 例如 文档上传页面的url 
     * templateId 模版id
     * lastId 上一条审核记录id 如果为空表示从第一级开始 
     * @return
     * flowNo 流程编码 
     * flowId 流程 id
     */
    public Map<String,String> generateAuditProcessIntf(Map<String,Object> context); 
    /**
     * 删除所有审批流程
     * @param flowNo
     */
    public void deleteAuditProcessIntf(String flowNo);
}

保存审批流模板时选择审批类型,如果选的回调函数,那么就需要用到下面这个接口

public interface QueryAuditedByIntf {
    /**
     * 根据 审核记录 返回 审核人id;
     * @param record
     * @return
     */
    public Integer queryAuditedBy(AuditRecord record);
}

实现这个回调函数有很多,我就举一个例子吧

public class QueryManagerImpl extends BaseStaticImpl implements
        QueryAuditedByIntf {

    @Override
    public Integer queryAuditedBy(AuditRecord record) {
        // TODO Auto-generated method stu
        TaskDetails taskDtl = (TaskDetails)publicService.lookUp(TaskDetails.class,record.getBillId());
        String hql="from SRProjectTeamPlayer where project.id="+ taskDtl.getSrProjectId() +" and dutiesType='02'";
        List<SRProjectTeamPlayer> teamLt = publicService.executeObjectSql(hql);
        if(teamLt!=null && teamLt.size()>0){
            return teamLt.get(0).getPlayerId();
        }
        return null;
    }
}

最精彩的来了,生成审批流的核心代码来了。当然说明一下,最重要的代码只有一个generateAuditProcessIntf,其他可以先无视。

public class AuditProcessImpl extends BaseStaticImpl implements
        AuditProcessIntf {
    //spring 依赖注入
    private ProcessTemplateIntf processTemplateService;


    public ProcessTemplateIntf getProcessTemplateService() {
        return processTemplateService;
    }
    public void setProcessTemplateService(ProcessTemplateIntf processTemplateService) {
        this.processTemplateService = processTemplateService;
    }

    /**
     * 生成 该项目相关联的所有审批记录
     */
    @Override
    public Map<String,String> generateAuditProcessIntf(Map<String,Object> context) {
        //返回值 返回一个map,key 为flowNo(审核流程唯一码)
        Map<String,String> result = new HashMap<String,String>();
        //接收的map参数
        String billName = (String)context.get("billName");
        String billNumber = (String)context.get("billNumber");
        Integer templateId= (Integer)context.get("templateId");
        String contentUrl = (String) context.get("contentUrl");
        String processUrl = (String) context.get("processUrl");
        Integer lastId  = (Integer) context.get("lastId");
        Integer billId  = (Integer) context.get("billId");//项目id
        String batchNo = (String)context.get("batchNo");
        Integer batchNum = (Integer)context.get("batchNum");
        String updateBillStatusIntf = (String) context.get("updateBillStatusIntf");
        HttpServletRequest req=(HttpServletRequest) context.get("req");

        //取得当前登录人
        PersonInfo employ=(PersonInfo)req.getSession().getAttribute(GlobalStaticKeys.LOGIN_PERSONINFO);

        AuditRecord last = null;
        if(lastId!=null && lastId.intValue()>0){
            last = (AuditRecord)publicService.lookUp(AuditRecord.class, lastId);
        }

        //获得审核模板明细
        List<ProcessTemplateDtl> templateLt = getProcessTemplateService().getProcessTemplateDtl(templateId);
        if(templateLt.size()<=0) return null;

        if(last != null){//更新上级审核流程状态为 已处理 
            last.setProcessStatus(SysGlobalStatic.SIGN_YES);
            publicService.mergeUpdate(last);
        }

        //生成当前所有的审核记录
        // flowNo为 唯一码,用来标记唯一的审核流程。
        String flowNo = getGenerateRuleIntf().generateNumber(AuditRecord.class.getName());
        for(int i =0 ;i<templateLt.size();i++){
            ProcessTemplateDtl dtl = templateLt.get(i);
            AuditRecord record = new AuditRecord();
            record.setName(dtl.getName());
            record.setBillName(billName);
            record.setBillNumber(billNumber);
            record.setBillId(billId);
            record.setTemplateId(templateId);
            record.setTemplateDtlId(dtl.getId());
            record.setContentUrl(contentUrl);
            record.setProcessUrl(processUrl);
            record.setUpdateBillStatusIntf(updateBillStatusIntf);
            record.setLastId(lastId);
            record.setLevel(dtl.getLevel());
            record.setCreatedById(employ.getId());
            record.setCreatedBy(employ.getName());
            record.setCreateDate(TypeConvert.formatDate(new Date()));
            record.setCreateTime(TypeConvert.formatTime(new Date()));
            record.setBatchNo(batchNo);
            record.setBatchNum(batchNum);
            if(i==0){//默认第一条记录为 待审核 
                record.setAuditStatus(SysGlobalStatic.STATUS_WAIT);//状态默认为待审核
            }
            if(ProcessTemplateDtl.ROLE.equals(dtl.getAuditSign())){//按角色审核 
                record.setRoleId(dtl.getRoleId());
                record.setRoleName(dtl.getRoleName());
            }else if (ProcessTemplateDtl.FUN.equals(dtl.getAuditSign())){//按回调函数审核  返回人员id
                QueryAuditedByIntf impl = (QueryAuditedByIntf)SpringUtil.getSpringBean(dtl.getInterfaceName());
                Integer employeeId = impl.queryAuditedBy(record);
                PersonInfo employee = (PersonInfo)publicService.lookUp(PersonInfo.class, employeeId);
                record.setEmployeeId(employeeId);
                record.setEmployeeName(employee.getName());

            }else if(ProcessTemplateDtl.EMPLOYEE.equals(dtl.getAuditSign())){//按人员 审核
                record.setEmployeeId(dtl.getEmployeeId());
                record.setEmployeeName(dtl.getEmployeeName());
            }
            record.setNumber(flowNo);
            //保存审核流程
            publicService.saveAutoIdObject(record);
        }
        result.put("flowNo", flowNo);
        return result;
    }



    /**
     * 通过flowNo 删除所有的审批流程
     */
    @Override
    public void deleteAuditProcessIntf(String flowNo) {
        StringBuilder hql = new StringBuilder("delete AuditRecord where number = '").append(flowNo).append("'");
        publicService.deleteObject(hql.toString());

    }

    /**
     * 审核记录
     */
    @Override
    public boolean otherOperate(ActionForm form, Map parameterMap) {
        AuditRecordForm userForm = (AuditRecordForm)form;
        //根据审核流程的id找到当前审核记录
        AuditRecord record = (AuditRecord)publicService.lookUp(AuditRecord.class, userForm.getId());
        record.setAuditDate(userForm.getAuditDate());
        record.setAuditedById(userForm.getAuditedById());
        record.setAuditedBy(userForm.getAuditedBy());
        record.setAuditStatus(SysGlobalStatic.STATUS_ALREADY);//设置当前流程审核状态为1,代表已审核
        record.setAuditResult(userForm.getAuditResult());//记录当前流程的审核结果
        record.setAuditComments(userForm.getAuditComments());
        //结束标志
        boolean over = false;
        //-- 保存附件
        String vPath = this.getFilePath();
        try {
            this.saveAttachment(userForm, vPath,record);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //审核通过
        if(SysGlobalStatic.SIGN_YES.equals(record.getAuditResult())){ 
            //--查找下一级审核记录 
            record.setBadgePictureFile(userForm.getBadgePictureFile());//保存签名文件 
            AuditRecord next = getNextAuditRecord(record.getNumber(), record.getLevel());
            if(next == null){ //审核结束 
                over = true;
            }else{
                next.setAuditStatus(SysGlobalStatic.STATUS_WAIT);//跟新下级为待审核
                publicService.mergeUpdate(next);
            }
        }else{//审核不通过 ,这个流程自己定义,是全部结束,还是本流程再审核
            over = true;        
            record.setProcessStatus(SysGlobalStatic.STATUS_WAIT);// 跟新处理状态为 待处理 
        }
        //更新审核流程
        publicService.mergeUpdate(record);
        if(over){//如果结束,这个是整个流程结束后的操作,有不通过的也算结束,这个根据业务修改
            //通过srping,getbean,得到对象
            UpdateBillStatusIntf impl = (UpdateBillStatusIntf)SpringUtil.getSpringBean(record.getUpdateBillStatusIntf());
            List lt = getAllRecord(record.getNumber());//全部的流程记录 
            impl.updateBillStatus(lt, record.getAuditResult());//更新单据的状态 
        }
        return true;
    }

    /**
     * 查找下一条审核记录
     * @param flowNo
     * @param level
     * @return
     */
    private AuditRecord getNextAuditRecord(String flowNo,Integer level){
        StringBuilder hql = new StringBuilder("select a from AuditRecord as a where a.number = '").append(flowNo).append("'");
        hql.append(" and a.level>").append(level);
        hql.append(" order by a.level asc ");
        List lt = publicService.executeObjectSql(hql.toString(), 0, 1) ;
        if(lt.size()>0 && lt.get(0)!=null){
            return (AuditRecord)lt.get(0);
        }
        return null;
    }

    /**
     * 得到所有审核记录
     * @param flowNo
     * @return
     */
    private List getAllRecord(String flowNo){
        StringBuilder hql = new StringBuilder("select a from AuditRecord as a where a.number = '").append(flowNo).append("'");
        hql.append(" order by a.level asc ");
        List lt = publicService.executeObjectSql(hql.toString()) ;
        return lt;
    }
}

ok 如此咱的审批流就封装完毕啦,随便搞一个测试一下,生成了审批流程之后,调用审批流程,这个测试比较简单,直接new的,用户可以根据需要自行调用

public static Map<String,String> getMap(){
        AuditProcessIntf ap=new AuditProcessImpl();
        Map<String,Object> context=new LinkedHashMap<String,Object>();
        context.put("billName","升仙贴报单");//项目名称
        context.put("billId", 111);//项目id
        context.put("billNumber", "");
        context.put("templateId", 7); //审批流程  模板id
        context.put("contentUrl", "");   //显示列表连接
        context.put("processUrl", "");  //上传文件连接
        context.put("lastId", 0);
        context.put("updateBillStatusIntf", "updateBillStatusService");
        context.put("batchNo","ddcc");//批次号
        context.put("batchNum",1);
        Map<String, String> result = ap.generateAuditProcessIntf(context);
        return result;
}

结果展示
AuditRecord
这里写图片描述
模板主表和明细
这里写图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值