Java实现自定义工作流

这篇文章实现java自定义工作流程,对工作流不太熟悉的可以先看下工作流相关文章:
工作流

相关表结构、实体创建

流程主表:tbl_workflow_requestbase(这里以项目工地工作流为例)

CREATE TABLE `tbl_workflow_requestbase` (
  `requestid` bigint(20) NOT NULL AUTO_INCREMENT,
  `projectno` varchar(255) COLLATE utf8_bin NOT NULL,
  `workflowid` bigint(20) NOT NULL,
  `entityid` bigint(20) NOT NULL,
  `requestname` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `currentoperatorid` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `status` smallint(6) DEFAULT NULL,
  `creator` varchar(50) COLLATE utf8_bin DEFAULT NULL,
  `createtime` datetime DEFAULT NULL,
  `lastoperatorid` bigint(20) DEFAULT NULL,
  `lastoperatetime` datetime DEFAULT NULL,
  PRIMARY KEY (`requestid`)
) ENGINE=InnoDB AUTO_INCREMENT=162561 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

entity

	@ApiModelProperty("流程ID")
    @Id
    @Column(name = "requestid")
    private String requestId;

    @ApiModelProperty("工地编码")
    @Column(name = "projectno")
    private String projectNo;

    @ApiModelProperty("流程类型ID")
    @Column(name = "workflowid")
    private String workflowId;

    @ApiModelProperty("业务ID")
    @Column(name = "entityid")
    private String entityId;

    @ApiModelProperty("流程标题")
    @Column(name = "requestname")
    private String requestName;

    @ApiModelProperty("当前操作人ID")
    @Column(name = "currentoperatorid")
    private String currentOperatorId;

    @ApiModelProperty("状态")
    @Column(name = "status")
    private Integer status;

    @ApiModelProperty("创建人")
    @Column(name = "creator")
    private String creator;

    @ApiModelProperty("创建时间")
    @Column(name = "createtime")
    private Date createTime;

    @ApiModelProperty("最后操作人ID")
    @Column(name = "lastoperatorid")
    private String lastOperatorId;

    @ApiModelProperty("最后操作时间")
    @Column(name = "lastoperatetime")
    private Date lastOperateTime;

然后是工作流节点表:tbl_workflow_requestnode

CREATE TABLE `tbl_workflow_requestnode` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `requestid` bigint(20) NOT NULL,
  `operatorid` varchar(500) COLLATE utf8_bin NOT NULL,
  `nodetype` smallint(6) DEFAULT NULL,
  `status` smallint(6) DEFAULT NULL,
  `sort` smallint(6) DEFAULT NULL,
  `createtime` datetime DEFAULT NULL,
  `modifytime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=54460 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

entity

	@ApiModelProperty("ID")
    @Id
    private Integer id;

    @ApiModelProperty("流程ID")
    @Column(name = "requestid")
    private String requestId;

    @ApiModelProperty("操作人")
    @Column(name = "operatorid")
    private String operatorId;

    @ApiModelProperty("节点类型")
    @Column(name = "nodetype")
    private Integer nodeType;

    @ApiModelProperty("状态")
    @Column(name = "status")
    private Integer status;

    @ApiModelProperty("顺序")
    @Column(name = "sort")
    private Integer sort;

    @ApiModelProperty("创建时间")
    @Column(name = "createtime")
    private String createTime;

    @ApiModelProperty("更新时间")
    @Column(name = "modifytime")
    private String modifyTime;

这里简单介绍下,工作流主表:用户发起的一条涉及多用户操作的流程,记录流程详细信息,通过requestId关联流程节点表信息。
流程节点信息表:记录各个节点用户的操作。

定义流程的方法,创建、执行、退回

	/**
     * 创建工作流
     */
    public ResponseResult create(CreateWorkflowVo createWorkflowVo) {
        // 同一个业务ID不能重复多线程创建流程
        synchronized (createWorkflowVo.getEntityId()) {
            return handleAction("/workflow/create", createWorkflowVo);
        }
    }

    /**
     * 执行工作流,往下一节点走
     */
    public ResponseResult execute(ExecuteWorkflowVo executeWorkflowVo) {
        // 同一条流程不能重复操作
        synchronized (executeWorkflowVo.getRequestId()) {
            return handleAction("/workflow/execute", executeWorkflowVo);
        }
    }

    /**
     * 退回工作流
     */
    public ResponseResult reject(RejectWorkflowVo rejectWorkflowVo) {
        // 同一条流程不能重复操作
        synchronized (rejectWorkflowVo.getRequestId()) {
            return handleAction("/workflow/reject", rejectWorkflowVo);
        }
    }

    private ResponseResult handleAction(String action, Object vo) {
        Asserts.notEmpty(uri, "请求地址");
        try {
            String res = restTemplate
                    .postForObject(uri + action, vo, String.class);
            if (!StringUtils.isEmpty(res)) {
                ResponseResult responseResult = JSONObject.parseObject(res, ResponseResult.class);
                return responseResult;
            }
        } catch (Exception ex) {
            log.error("调用工作流服务失败:action=" + action, ex);
        }
        throw new GlobalException("12000", "调用工作流服务失败,action=" + action + ":无法获取请求数据");
    }

执行对应流程创建、执行、退回的方法,会调用执行定义好的一个工作流工程的回调函数,把函数的指针(地址)作为参数传递给另一个函数,返回结果。uri=工程的ip+端口
如下:

 /**
     * 创建工作流
     *
     * @param createWorkflowVo
     * @return
     */
    @PostMapping("create")
    public ResponseResult<String> create(@RequestBody CreateWorkflowVo createWorkflowVo) {
        return processService.createFlow(createWorkflowVo);
    }

    /**
     * 流程往下走
     *
     * @param executeWorkflowVo
     * @return
     */
    @PostMapping("execute")
    public ResponseResult<String> execute(@RequestBody ExecuteWorkflowVo executeWorkflowVo) {
        return processService.executeFlow(executeWorkflowVo);
    }

    /**
     * 退回
     *
     * @param rejectWorkflowVo
     * @return
     */
    @RequestMapping("reject")
    public ResponseResult<String> reject(@RequestBody RejectWorkflowVo rejectWorkflowVo) {
        return processService.rejectFlow(rejectWorkflowVo);
    }

service代码实现:

	//创建工作流
	@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ResponseResult<String> createFlow(CreateWorkflowVo createWorkflowVo) {
        log.info("请求参数: {}", createWorkflowVo);
        assertNotNull(createWorkflowVo);

        WorkflowBase base = workflowBaseMapper
                .selectByPrimaryKey(createWorkflowVo.getWorkflowBaseId());
        if (base == null) {
            throw new GlobalException("120004", "找不到Workflow base配置表信息");
        }

        // 回调地址不能为空
        Asserts.notNull(base.getActionUrl(), "actionUrl");

        WorkflowRequestBase srchBase = new WorkflowRequestBase();
        srchBase.setEntityId(createWorkflowVo.getEntityId());
        srchBase.setStatus(0);
        Integer count = workflowRequestBaseMapper.selectCount(srchBase);
        if (count != null && count > 0) {
            throw new GlobalException("120011", "同一条业务不能重复创建流程");
        }

        WorkflowRequestBase requestBase = setRequestBase(createWorkflowVo);

        // 插入流程审批表
        workflowRequestBaseMapper.insertReturnKeys(requestBase);
        log.info("id = {}", requestBase.getRequestId());
        if (requestBase.getRequestId() != null && requestBase.getRequestId().length() > 0) {

            List<String> requestNodes = createWorkflowVo.getRequestNodes();

            // 插入流程节点表
            int sort = 0;
            requestNodes.add("0");// 归档节点
            List<WorkflowRequestNode> nodesList = new ArrayList<WorkflowRequestNode>();
            for (String userid : requestNodes) {
                WorkflowRequestNode node = new WorkflowRequestNode();
                node.setRequestId(requestBase.getRequestId());
                node.setOperatorId(userid);
                node.setNodeType("0".equalsIgnoreCase(userid) ? 1 : 0);
                node.setStatus(0);
                node.setSort(sort++);
                nodesList.add(node);
            }

            workflowRequestNodeMapper.batchInsert(nodesList);

        } else {
            throw new GlobalException("120005", "无法获取Request ID");
        }

        return ResponseResult.success(String.valueOf(requestBase.getRequestId()));
    }



    //执行流程
    /**
     * 流程往下走
     *
     * @param executeWorkflowVo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ResponseResult executeFlow(ExecuteWorkflowVo executeWorkflowVo) {
        WorkflowRequestBase requestBase = getRequestBase(executeWorkflowVo.getRequestId());
        // 如果工作流的状态不对,不能继续操作
        if (requestBase.getStatus() != 0) {
            throw new GlobalException("120010", "该工作流可能已归档,无法继续操作");
        }
        // 只有当前操作人才能操作,防重复提交
        if (!requestBase.getCurrentOperatorId()
                .equalsIgnoreCase(String.valueOf(executeWorkflowVo.getCurrentOperatorId()))) {
            throw new GlobalException("120007", "当前操作人不合法");
        }
        WorkflowRequestNode nextNode = null;
        // 如果需要插入节点
        if (executeWorkflowVo.isInsertNode()) {
            if (CollectionUtils.isEmpty(executeWorkflowVo.getNodes())) {
                throw new GlobalException("120011", "插入的节点操作人不能为空");
            }
            // 获取当前操作人节点及以后的节点
           List<WorkflowRequestNode> afterNodes = workflowRequestNodeMapper.
           selectNextOperator(executeWorkflowVo.getRequestId(),
           executeWorkflowVo.getCurrentOperatorId());

            Integer initSort = afterNodes.get(0).getSort();
            List<String> nodes = executeWorkflowVo.getNodes();

            List<WorkflowRequestNode> insertNodes = Lists.newArrayList();
            for (int i = 0; i < nodes.size(); i ++) {
                initSort ++;
                WorkflowRequestNode eachNode = new WorkflowRequestNode();
                eachNode.setRequestId(executeWorkflowVo.getRequestId());
                eachNode.setNodeType(0);// 不是归档节点
                eachNode.setOperatorId(executeWorkflowVo.getNodes().get(0));
                eachNode.setStatus(0);
                eachNode.setSort(initSort);
                eachNode.setCreateTime(DateUtil.getCurrentDateTime());
                eachNode.setModifyTime(DateUtil.getCurrentDateTime());
                if (i == 0) {
                    nextNode = eachNode;
                }
                insertNodes.add(eachNode);
            }
            // 将当前操作人节点后面的节点sort都往后推移
            for (WorkflowRequestNode node : afterNodes) {
                initSort ++;
                node.setSort(initSort);
                // 更新
                workflowRequestNodeMapper.updateByPrimaryKeySelective(node);
            }
            // 插入节点
            workflowRequestNodeMapper.batchInsert(insertNodes);
        } else {

            // 查询下一节点操作人
            List<WorkflowRequestNode> nextNodes = workflowRequestNodeMapper
                    .selectNextOperator(executeWorkflowVo.getRequestId(),
                            executeWorkflowVo.getCurrentOperatorId());
            if (CollectionUtils.isEmpty(nextNodes)) {
                throw new GlobalException("120008", "流程下一节点为空!");
            }
            nextNode = nextNodes.get(0);
        }
        Integer nextNodeType = nextNode.getNodeType();
        String nextOperatorId = nextNode.getOperatorId();

        // 修改当前操作人的状态为审核通过
        WorkflowRequestNode requestNode = new WorkflowRequestNode();
        requestNode.setStatus(1);
        requestNode.setModifyTime(DateUtil.getCurrentDateTime());
        updateRequestNode(requestNode, executeWorkflowVo.getRequestId(),
                executeWorkflowVo.getCurrentOperatorId());

        // 修改流程审批表的当前操作人为查询出来的下一节点操作人
        WorkflowRequestBase updateBase = new WorkflowRequestBase();
        updateBase.setCurrentOperatorId(nextOperatorId);
        updateBase.setLastOperatorId(executeWorkflowVo.getCurrentOperatorId());
        updateBase.setLastOperateTime(DateUtil.currentDate());
        updateRequestBase(updateBase, executeWorkflowVo.getRequestId(),
                executeWorkflowVo.getCurrentOperatorId());

        // 记录一条操作日志
        recordRequestLog(executeWorkflowVo.getRequestId(), executeWorkflowVo.getCurrentOperatorId(),
                nextOperatorId, 1, "已审批");

        // 如果下一节点是归档节点,则直接归档
        if (nextNodeType == 1) {
            boolean flag = finish(requestBase.getWorkflowId(), requestBase.getEntityId(),
                    executeWorkflowVo.getRequestId());
            log.info("归档结果,{}", flag);
        }
        return ResponseResult.success();
    }

/**
     * 流程退回
     *
     * @param rejectWorkflowVo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ResponseResult rejectFlow(RejectWorkflowVo rejectWorkflowVo) {
        WorkflowRequestBase requestBase = getRequestBase(rejectWorkflowVo.getRequestId());

        // 如果工作流的状态不对,不能继续操作
        if (requestBase.getStatus() != 0) {
            throw new GlobalException("120010", "该工作流可能已归档,无法继续操作");
        }
        // 只有当前操作人才能操作,防重复提交
        if (!requestBase.getCurrentOperatorId()
                .equalsIgnoreCase(String.valueOf(rejectWorkflowVo.getCurrentOperatorId()))) {
            throw new GlobalException("120007", "当前操作人不合法");
        }
        // 修改当前操作人的状态为审核通过
        WorkflowRequestNode requestNode = new WorkflowRequestNode();
        requestNode.setStatus(-1);
        requestNode.setModifyTime(DateUtil.getCurrentDateTime());
        updateRequestNode(requestNode, rejectWorkflowVo.getRequestId(),
                rejectWorkflowVo.getCurrentOperatorId());

        // 修改流程审批表的当前操作人为查询出来的下一节点操作人
        WorkflowRequestBase updateBase = new WorkflowRequestBase();
        updateBase.setStatus(-1);
        updateBase.setLastOperatorId(rejectWorkflowVo.getCurrentOperatorId());
        updateBase.setLastOperateTime(DateUtil.currentDate());
        updateRequestBase(updateBase, rejectWorkflowVo.getRequestId(),
                rejectWorkflowVo.getCurrentOperatorId());
        // 记录一条操作日志
        recordRequestLog(rejectWorkflowVo.getRequestId(), rejectWorkflowVo.getCurrentOperatorId(),
                null, 1, "已退回:" + rejectWorkflowVo.getRejectNote());
        boolean flag =
                callbackAction(requestBase.getWorkflowId(), requestBase.getEntityId(), -1, rejectWorkflowVo.getRejectNote());
        log.info("退回结果,{}", flag);
        return ResponseResult.success();
    }

相关Vo

创建工作流

public class CreateWorkflowVo implements Serializable {

    @ApiModelProperty("流程标题")
    private String requestName;

    @ApiModelProperty("哪种类型的流程")
    private String workflowBaseId;

    @ApiModelProperty("实际业务ID")
    private String entityId;

    @ApiModelProperty("工地编码")
    private String projectNo;

    @ApiModelProperty("提交人ID")
    private String creator;

    @ApiModelProperty("流程节点处理人")
    private List<String> requestNodes;

}

执行工作流,走向下一节点

public class ExecuteWorkflowVo implements Serializable {

    /**
     * 工作流ID
     */
    private String requestId;

    /**
     * 当前操作人ID
     */
    private String currentOperatorId;

    /**
     * 是否插入节点
     */
    private boolean insertNode;

    /**
     * 节点
     */
    private List<String> nodes;

}

退回工作流

public class RejectWorkflowVo implements Serializable {

    /**
     * 工作流ID
     *
     */
    private String requestId;

    /**
     * 当前操作人ID
     */
    private String currentOperatorId;

    /**
     * 退回原因
     */
    private String rejectNote;

}

工作流流程用户在创建、往下执行、退回调用对应的自定义工作流方法,举例:一条由工地项目经理发起的流程,设置涉及的流程节点:项目经理、项目主管、片区工程经理、业主。执行创建流程:

				CreateWorkflowVo workflow = new CreateWorkflowVo();
                workflow.setProjectNo(contractMeasure.getClientNo());
                workflow.setEntityId(contractMeasure.getId());
                workflow.setCreator(Integer.toString(xmjl));
                workflow.setWorkflowBaseId("12");
                workflow.setRequestName("关于××审批");

                //创建审批节点
                List<String> requestNodes = new ArrayList<String>();
                //项目主管节点
                requestNodes.add(Integer.toString(xmzg));
                //添加业主节点
                requestNodes.add(contractMeasure.getClientNo());
                workflow.setRequestNodes(requestNodes);

                ResponseResult result = workflowUtil.create(workflow);

查看流程主表,会有一条新的记录
在这里插入图片描述
查看requestid关联的流程节点表
在这里插入图片描述
后面节点审批就省略了,无非也是封装对应的参数Vo,调用流程方法。

  • 6
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要使用Java实现自定义导入功能,需要以下步骤: 1. 定义一个类来描述你要导入的数据,这个类必须是可序列化的。 2. 实现一个自定义的文件导入类,这个类必须能够读取文件,并将数据映射到你定义的类。 3. 使用Java的流机制来读取文件,并使用一个缓冲流来加速读取过程。 4. 将读取到的数据存储到一个数据结构中,例如List或Map。 5. 实现一个方法,用于将数据导入到你的数据库或其他存储系统中。 以下是一个简单的示例代码: ``` import java.io.*; import java.util.*; public class ImportData { public static void main(String[] args) throws IOException { // 定义数据结构 List<MyData> dataList = new ArrayList<>(); // 读取文件 try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) { String line; while ((line = reader.readLine()) != null) { // 将文件中的数据映射到类 String[] fields = line.split(","); MyData data = new MyData(); data.setField1(fields[0]); data.setField2(fields[1]); // 将数据存入数据结构 dataList.add(data); } } // 导入数据到数据库 importData(dataList); } private static void importData(List<MyData> dataList) { // 实现数据导入的代码 } } class MyData implements Serializable { private String field1; private String field2; public String getField1() { return ### 回答2: 要使用Java实现自定义导入功能,可以按照以下步骤进行操作: 1. 定义自定义导入格式:要实现自定义导入功能,首先需要定义导入格式。可以选择使用文件路径、包名、类名等方式作为导入的格式。例如,可以定义自定义导入格式为"custom.import.类名",其中"classname"为要导入的类名。 2. 解析自定义导入:接下来,需要编写代码解析自定义导入。可以使用正则表达式或字符串处理等方式解析导入格式,获取到要导入的类名。 3. 导入指定类:根据解析得到的类名,使用Java的反射机制进行类的导入。可以使用`Class.forName(className)`方法或`import`关键字来实现具体的导入操作。 4. 使用导入的类:在导入完成后,可以直接使用导入的类进行开发工作。可以调用类的方法、访问类的属性等。 需要注意的是,自定义导入功能在实际项目中可能需要进行一些额外的处理,例如处理类路径、处理冲突等。此外,自定义导入功能也需要考虑安全性,避免恶意导入或引入不安全的类。 此外,为了使用自定义导入功能,还需要将自定义导入的相关逻辑集成到 Java 项目中,例如通过自定义类加载器、插件等方式实现。对于大型项目或框架,可能还需要提供更高级别的功能,例如自动导入、按需加载等。 ### 回答3: 使用Java实现自定义导入功能,可以通过以下步骤来实现: 1. 创建一个自定义的导入类。该类需要实现 ImportDeclaration 接口,并重写其中的方法。其中,ImportDeclaration 接口定义了 importDeclaration() 方法,用于处理自定义导入逻辑。 2. 在 importDeclaration() 方法中,按照自定义的规则,解析导入的内容。可以使用正则表达式或其他方式,将导入的内容拆分成包名、类名等部分。例如,可以使用正则表达式匹配 import 语句中的包名和类名,并将其提取出来。 3. 根据解析出来的包名和类名,使用反射或其他方式加载相应的类。可以使用 Class.forName() 方法加载类,并将加载得到的 Class 对象存储到一个自定义的类加载器中。这样,在后续的代码中就可以通过该类加载器来获取对应的类。 4. 实现自定义导入逻辑。根据导入内容中的包名和类名,从自定义类加载器中获取对应的 Class 对象,并使用该对象进行操作。例如,可以使用反射来调用类中的方法、读取类的属性等。 通过以上步骤,就可以实现自定义的导入功能了。在解析导入语句时,可以根据自己的需要定义不同的规则,并在 importDeclaration() 方法中处理相应的逻辑。需要注意的是,自定义导入功能可能会引入一些安全风险,因此在实现时需要注意对导入内容的校验和过滤,以防止恶意代码的执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值