ZeroCloud 低代码开发平台
首页
用户手册
开发者手册
首页
用户手册
开发者手册
  • 用户手册

    • 产品简介
    • 快速入门
    • 工作台
    • 组织管理
    • 数据管理
    • 业务建模

      • 表单管理

        • 表单设计
        • 组件配置

          • 组件属性
          • 组件校验
          • 组件事件
          • 组件样式
        • 基础组件

          • 标题
          • 文字
          • 图片
          • 按钮
          • 链接
          • 分割线
          • 网页
        • 布局组件

          • 表单区块
          • 网格布局
          • 标签页
          • 明细表格
          • 明细区域
        • 功能组件

          • 输入文本
          • 日期时间
          • 单项选择
          • 多项选择
          • 下拉选择
          • 计数器
          • 开关
          • 滑块
          • 评分
          • 上传附件
          • 选择用户
          • 选择部门
          • 选择数据
          • 选择颜色
          • 富文本
          • UEditor
          • 条形码
          • 二维码
          • 添加明细行
          • 流程审批
          • 历史流程
      • 表单模型

        • 模型设计
        • 用法示例
      • 视图管理

        • 视图设计
        • 基础组件

          • 文字
          • 按钮
          • 图片
          • 链接
          • 分割线
          • 标签
          • 网页
          • Html
        • 布局组件

          • 页头
          • 容器
          • 网格
          • 区块
          • 卡片
          • 标签页
        • 模态组件

          • 对话框
          • 抽屉
        • 数据展示

          • 表格
          • 数据表格
          • 树
          • 数据树
          • 轮播图
          • 日历
          • 图表
          • 时间线
          • 步骤条
          • 宫格
          • 进度条
          • 分页
          • 标记
        • 数据输入

          • 表单/表单项
          • 文本框
          • 开关
          • 日期选择
          • 单项选择
          • 多项选择
          • 下拉选择
          • 滑块
          • 评分
      • 报表管理
    • 流程设计

      • 流程定义

        • 流程设计
        • 节点配置
        • 办理人配置
      • 决策定义
      • 我的任务
      • 流程运维
      • 流程监控
    • 应用管理
    • 安全管理

      • 用户组
      • 安全角色
      • 权限资源
      • 权限分配
    • 系统监控

      • 系统监控
  • 开发者手册

    • 安装部署

      • 环境要求
      • 生产环境
    • 技术架构

      • 技术栈
    • API 文档

      • 概述
      • PC端 JS-API

        • 全局变量
        • PC表单
        • PC视图
      • 移动端 JS-API

        • 全局变量
        • 移动表单
        • 移动视图
      • 服务端 API

    • 常用案例

      • PC表单

        • 表单组件

          • 明细表格
        • 表单校验
        • 生命周期
        • 组件事件
        • 扩展方法
      • PC视图

        • 视图组件

          • 数据表格
          • 上传组件
        • 组件事件
        • 扩展方法
        • 生命周期
        • 视图样式
        • 系统案例

          • 消息提醒
          • 操作确认
          • 全屏加载
          • 批量删除
          • 高级搜索
          • 远程搜索
          • 组件间传值
          • 数据表格默认全选
          • 时间范围
          • 附件下载\预览
          • 模态层动态展示图片
          • 表格重复行合并行
          • 评分禁用
          • 右键树菜单
          • 视图中打开视图
      • 自定义服务

        • 系统表单
        • 系统视图
        • 流程服务
        • 附件文件
        • 开始
        • 环境搭建
        • Swagger 文档
        • 前台通用请求方式
        • 自定义返回值
        • 按钮点击给明细表赋值
        • 表单展示接口报错
        • 数据选择使用ajax
        • 数据源使用后台接口
        • 根据临时变量的值给后台传参
        • 批量删除
        • 删除按钮
        • 入库判断库存
        • 表单调用后台自定义接口
        • 后台发起流程
        • 出库校验
  • 常见问题

    • 问题反馈

后台发起流程

业务需求

采购明细单中增加一个处理人字段,每行采购物料都要通知这个指定人员处理,当采购申请单审核通过后,会根据明细表行数,自动发起流程

发起原理

f12抓取

f12打开调试,正常发起流程,我们可以发现就是正常发起http请求,调用create接口。我们使用后台调用效果应该一致

接口测试工具发起流程

根据f12抓取的信息,就可以使用Apipost等接口调用工具发起一个新流程。当然也就可以用java后台发起。

基本信息
接口URL: http://localhost:8008/instance/create
请求方式: POST
Content-Type: application/json

header

参数名示例值参数类型是否必填参数描述
ZctokenGh8pNiL9YNbbQTIiYGCpRAZYv6yyTtnv否暂无描述

body参数及说明

{
	"definitionKey": "Process_R6KpeaUqiJU0BNXvWuNcZ",//流程编码
	"version": null,
	"initiator": {
		"ouMemberSid": "be7cbd6b-3a65-474f-9d06-70c6a278c1f6"//携带部门职位等信息的人员编码
	},
	"formData": {
		"erp": {
			"buyer": [
				{
					"__zcRowGuid": "h2maR6gx93B1A2zc-vJvT",
					"user_name": "11",
					"item_name": "11",
					"qty": null,
					"busniess_key": null,
					"id": null,
					"sn": null,
					"business_key": null
				}
			]
		}
	}
}

流程准备

当然想要从后台发起流程,首先我们要有一个流程。 这里我新建了一个采购人员,很简单,只有三个字段。

审批人设置为数据表内的账号,使用采购人员就可以,方便观察效果。

之后后台发起流程,想要知道发起哪个流程,就需要流程编码。流程编码就在下图所在位置。

后端接口

调用逻辑,ZeroCloud首先调用OpenFlowController,使用一个Map接受参数。
为了方便演示此案例业务逻辑我直接写在了controller里,编写了一个request方法。
request方法里有两点需要注意的。

  1. 请求流程接口需要sid,因为流程启动不光需要一个人的账号信息,还需要这个人的职位信息,部门信息等等。所以我们要使用 账号换取sid。 使用的方式就是微服务之间的调用,feign。
    接口信息可以从上文的Api文档中查看。

  2. hutool工具类,我使用hutool工具类的jsonObject,把我利用f12从后台抓取到的发起[采购人员]流程的请求体,转成了jsonObject,之后修改了这个jsonObject对象作为新的请求体。

  3. 使用hutool工具类发起了http请求,来发起流程。

OpenFlowController


package com.zerocloud.custom.service.api.controller;




import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zerocloud.common.core.model.ou.ZcOUMember;
import com.zerocloud.common.core.model.ou.ZcUser;

import com.zerocloud.common.core.model.result.ZcResult;
import com.zerocloud.custom.service.api.feign.RemoteSystemService;
import com.zerocloud.custom.service.api.model.ApiResponse;

import com.zerocloud.custom.service.api.service.StockService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@Api(tags = "打开流程")
@RestController
@RequestMapping("/openFlows")
public class OpenFlowController {

    private final RemoteSystemService remoteSyStemService;

    @Autowired
    public OpenFlowController(StockService stockService,RemoteSystemService remoteSyStemService) {
        this.remoteSyStemService = remoteSyStemService;
    }


    @PostMapping("/byName")
    @ApiOperation("根据用户名称发起流程")
    public ZcResult<String> openFlow(@RequestBody Map map) {
        //获取流程推送的参数
        String string = map.toString();
        //转换成jsonObject
        JSONObject param = JSONUtil.parseObj(map);

        JSONArray buyers = param.getJSONArray("buyer");
        String zctoken =  param.getStr("Zctoken");
        for (Object obj : buyers) {
            JSONObject buyer = (JSONObject) obj;
            //通过http调用的方式发起流程
            this.request(buyer,zctoken);
        }

        return ZcResult.success("接口调用成功");
    }

    //利用hutool工具类处理字符串,把json格式的字符串直接转换成jsonObject
    //利用hutool工具类发起http请求
    public void request(JSONObject buyerParam,String zctoken){
        // 在这里处理每个 buyer 对象
        String userName =  buyerParam.getStr("user_name");
        String item_name =  buyerParam.getStr("item_name");
        String qty = buyerParam.getStr("qty");
        //根据用户名称获取用户信息
        ZcResult<List<ZcOUMember>> ouUser = remoteSyStemService.getOuUser(userName);
        List<ZcOUMember> data = ouUser.getData();
        //获取sid
        String ouMemberSid = data.get(0).getOuMemberSid();

        // 创建流程url
        String url = "http://localhost:8004/process/instance/create";
        // 请求参数 从f12抓到的
        String requestBody = "{\"definitionKey\":\"Process_R6KpeaUqiJU0BNXvWuNcZ\",\"version\":null,\"initiator\":{\"ouMemberSid\":\"be7cbd6b-3a65-474f-9d06-70c6a278c1f6\"},\"formData\":{\"erp\":{\"buyer\":[{\"__zcRowGuid\":\"h2maR6gx93B1A2zc-vJvT\",\"user_name\":\"11\",\"item_name\":\"11\",\"qty\":null,\"busniess_key\":null,\"id\":null,\"sn\":null,\"business_key\":null}]}}}";
        // 将请求体字符串转换为JSON对象,直接修改对象,就不用new了,直接new也一样
        JSONObject jsonBody = new JSONObject(requestBody);
        JSONObject initiator = jsonBody.getJSONObject("initiator");
        initiator.set("ouMemberSid",ouMemberSid);
        jsonBody.set("initiator",initiator);
        JSONObject formData = jsonBody.getJSONObject("formData");
        JSONObject erp = formData.getJSONObject("erp");
        JSONArray buyer = erp.getJSONArray("buyer");

        // 获取buyer数组中的第一个对象
        JSONObject buyerObject = buyer.getJSONObject(0);
        // 删除__zcRowGuid属性  若无子表嵌套,不需要这个字段
        buyerObject.remove("__zcRowGuid");

        // 给buyer对象重新赋值
        buyerObject.put("user_name", userName);
        buyerObject.put("item_name", item_name);
        buyerObject.put("qty", qty);
        //放回数组结构中
        buyer.put(0, buyerObject);

        erp.set("buyer",buyer);
        formData.set("erp",erp);
        jsonBody.set("formData",formData);

        String string = jsonBody.toString();

        // 请求头
        HttpRequest request = HttpRequest.post(url)
                .header("Zctoken", zctoken)
                .body(jsonBody.toString());

        // 发送请求
        HttpResponse response = request.execute();

        // 获取响应结果
        int statusCode = response.getStatus();
        String responseBody = response.body();

        // 打印响应结果
        System.out.println("Status code: " + statusCode);
        System.out.println("Response body: " + responseBody);

    }

}

RemoteSystemService

SpringCloud 微服务之间的远程调用,实际就是http请求。这里使用了Feign,使得远程调用就像调用方法一样容易。大家根据接口文档,使用http调用可以达成一样的效果。

package com.zerocloud.custom.service.api.feign;

import com.zerocloud.common.core.model.ou.ZcOUMember;
import com.zerocloud.common.core.model.ou.ZcUser;
import com.zerocloud.common.core.model.result.ZcResult;
import com.zerocloud.custom.service.api.model.ApiResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient(name = "zerocloud-auth")
public interface RemoteSystemService {

    @GetMapping("ou-member/user")
        //通过用户账号,获取用户信息
        //接口信息从swagger里找一下
        //http://localhost:8002/swagger-ui.html#/%E9%83%A8%E9%97%A8%E6%88%90%E5%91%98/kUsingGET
    ApiResponse<ZcUser> getOuUserInfo(@RequestParam("userName") String userName);


    @GetMapping("ou-member/search")
        //通过用户账号,获取部门成员信息
        //接口信息从swagger里找一下
        //http://localhost:8002/swagger-ui.html#/%E9%83%A8%E9%97%A8%E6%88%90%E5%91%98/kUsingGET
    ZcResult<List<ZcOUMember>> getOuUser(@RequestParam("keyword") String userName);
}

前台配置

下面这段代码的逻辑就是封装了一个map,携带Zctoken及一个数组。循环明细行给这个数组赋值。后台收到这些参数,用来发起一个新流程。

//这版groovy上下文用*引入的jackson对象,不写全称找不到对象
//这版也不要尝试import 会报错
//再过一两个版本会换成利用js上下文结构选择的形式,直接cv就可以。

com.fasterxml.jackson.databind.node.ObjectNode map = new com.fasterxml.jackson.databind.ObjectMapper().createObjectNode();
map.put("Zctoken", loginUser.getTokenValue());
com.fasterxml.jackson.databind.node.ArrayNode buyers = new com.fasterxml.jackson.databind.ObjectMapper().createArrayNode();
for (java.util.Map < String, Object > row : formData.get("zerocloud_data").get("purchase_t")) {
  com.fasterxml.jackson.databind.node.ObjectNode buyer = new com.fasterxml.jackson.databind.ObjectMapper().createObjectNode();
  com.fasterxml.jackson.databind.JsonNode rowNode = new com.fasterxml.jackson.databind.ObjectMapper().valueToTree(row);
  buyer.put("user_name", rowNode.get("work_user"));
  buyer.put("item_name", rowNode.get("item_name"));
  buyer.put("qty", rowNode.get("qty"));
  buyers.add(buyer);
}
map.put("buyer", buyers)
return map.toString();

正确实现方式

以上实现方式是有漏洞的,究其原因是因为获取OuMemberSid那一步,调用的接口实际是一个模糊搜索 举个例子,我传递y1,返回数组里会有y10,y11,y12用户。 而且会有一人多职的情况存在,一个userName对应多个ouMemberSid,那么数组里的对象会更多。 那针对以上业务需求显然不太合适了。

以下是正确实现思路,上文示例可以作为Feign调用的示例。

修改表单

原先直接填写UserName的位置,替换为使用选择用户组件,使用选择用户组件可以直接获得OuMemberSid

这样我们传递给后台的work_user,直接就是OuMemberSid,无需再通过接口查询了。 后台代码可以把之前案例中通过feign调用接口获取OuMemberSid的位置直接换成前台传递的参数。 这样流程发起人就可以锁定了

Prev
表单调用后台自定义接口
Next
出库校验