springboot+activiti7+react实现模仿钉钉功能的审批流(十三、api sdk开发过程)

在上面的《十一、外部系统通过api发起流程》和《十二、通知外部系统流程状态变化》两个步骤中看出:
外部系统对接流程平台,需要编写3个操作:
1.向流程平台发起流程
2.给流程平台回调的post接口
3.用实例id从流程平台查询流程状态
为了方便对接,开发了一个简易的sdk,方便外部系统对接,钉钉也是类似的有sdk。

sdk核心方法:
1.发起流程
2.根核流程平台分配给外部系统的appId、appSecret生成接口签名

sdk代码模块:

签名工具类:

/**
 * @Author: ltx
 * @Date: 2020-10-20 17:29:40
 * @Description: 签名工具类
 */

public class SignUtils {
    private static final Logger log = LoggerFactory.getLogger(SignUtils.class);
    /**
     * 生成签名header
     * @param appId
     * @param appSecret
     * @param body
     * @return Map<String, String>
     */
    public static Map<String, String> sign(String appId, String appSecret, Map<String, Object> body) {
        if (StrUtil.isBlank(appId)) {
            throw new ActException("appId不能为空!");
        }
        if (StrUtil.isBlank(appSecret)) {
            throw new ActException("appSecret不能为空!");
        }
        //参数-header
        Map<String, String> header = new HashMap<>(16);
        //app标识-标识来自于哪个第三方应用
        header.put("appId", appId);
        //使用雪花算法生成流水id
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        header.put("nonce", String.valueOf(snowflake.nextId()));
        //时间戳-接口有效期,比如此调用超过10分钟失效
        header.put("timestamp", "" + System.currentTimeMillis());

        String stringA = MapUtil.sortJoin(header, "&", "=", true);
        String stringB = MapUtil.sortJoin(body, "&", "=", true);

        //生成签名--使用摘要算法
        String stringSignTemp = stringA + stringB + appSecret;

        //头数据字符串+请求参数字符串+key
        String sign = SecureUtil.sha256(stringSignTemp);
//        log.info("sign: {}", sign.toUpperCase());
//        头里面放入sign
        header.put("sign", sign.toUpperCase());
//        String stringH = MapUtil.sortJoin(header, "&", "=", true);
//        log.debug("header: {}", stringH);
//        log.debug("body: {}", stringB);
        return header;
    }

    /**
     * 生成签名header
     * @param appId
     * @param appSecret
     * @return Map<String, String>
     */
    public static Map<String, String> sign(String appId, String appSecret) {
        return sign(appId, appSecret, null);
    }
}

审批流sdk测试用例:

/**
 * 审批流sdk测试
 * @Author: ltx
 * @Date: 2020/10/20 09:44
 * @Description:
 */
public class ActTest {
    private static final Logger log = LoggerFactory.getLogger(ActTest.class);
    /**
     * 这几个建议放配置文件
     */
    private String appId = "869988981";

    private String appSecret = "XAycmHSwRPkLOagfPKqJpDvUVRWdGVRdWi5y247wzq41l94KQIRQ6FmrPW489Mm9";

    //审批流url
    private String serverUrl = "http://localhost:8888";

    //启动流程接口
    private String startProcessInstanceUrl = "/openApi/startProcessInstance";

    //查询流程状态接口
    private String getProcessInstanceStatusById = "/openApi/getProcessInstanceStatusById/";

    //查询流程明细接口
    private String getProcessInstanceById = "/openApi/getProcessInstanceById/";
    /**
     * 发起流程
     */
    @Test
    public void startProcessInstance() {
        //请求地址
        String apiUrl = serverUrl + startProcessInstanceUrl;
        //生成签名客户端
        IActClient actClient = new ActClientImpl(apiUrl, appId, appSecret);

        //构建发起流程的对象
        StartActDataDto startActDataDto = new StartActDataDto();
        //类型编码
        startActDataDto.setProcessCode("89171873-0076-4E81-8652-48D2A0B724DA");
        //发起人id
        startActDataDto.setStartUserId(1019);
        //审批实例发起人的手机号, 发起流程, startUserId和startUserPhone, 要必填一个
//        startActDataDto.setStartUserPhone("19107220912");
        //表单数据
        HashMap<String, Object> formValues = new HashMap<>(16);
        formValues.put("事由", "提点用用, 望批准!");
        formValues.put("提现金额", 88);
        startActDataDto.setFormValues(formValues);

        String processInstanceId = actClient.startProcessInstance(startActDataDto);
        log.info("实例id: {}", processInstanceId);
    }

    /**
     * 查询流程状态
     */
    @Test
    public void getProcessInstanceStatusById() {
        //请求地址
        String apiUrl = serverUrl + getProcessInstanceStatusById;
        //生成签名客户端
        IActClient actClient = new ActClientImpl(apiUrl, appId, appSecret);
        PostDataDto postDataDto = actClient.getProcessInstanceStatusById("39cd9ab7-1371-11eb-853f-1831bfdf48c6");
        log.info("流程状态对象: {}", postDataDto);
    }
}

提供给流程平台post回调的接口实例:

@ApiOperation("xxxx回调接口")
@PostMapping(value = "/actBack")
public R<String> miaodiApplyLogNewReview(@RequestBody @ApiParam(value = "审批流程返回数据") PostDataDto postDataDto)throws Exception {
	log.info("回调postDataDto: {}", postDataDto);
	//TODO 你的代码
	return R.ok("ok");
}

PostDataDto实体对象:

@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "回调业务系统参数dto")
public class PostDataDto implements Serializable {
    @ApiModelProperty(value = "流程实例id")
    private String processInstanceId;

    @ApiModelProperty(value = "审批流的唯一码")
    private String processCode;

    @ApiModelProperty(value = "状态(1:审核通过,2:审核不通过,3:待审核,4:已撤单)")
    private Integer status = -1;

    @ApiModelProperty(value = "实例创建时间")
    private Date createTime;

    @ApiModelProperty(value = "审批结束时间")
    private Date finishTime;
}

sdk打包时候注意:打包配置将sdk的pom项目依赖打到一个jar包里

可以打下源码包,方便外部系统查看sdk源码,最终打包文件:

外部系统使用sdk:

1.将act-sdk-1.0.0-jar-with-dependencies.jar放项目的lib目录下。

2.pom.xml里面增加:
<!--审批流sdk-->
<dependency>
    <groupId>com.qmy</groupId>
    <artifactId>act-sdk</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${pom.basedir}/lib/act-sdk-1.0.0-jar-with-dependencies.jar</systemPath>
</dependency>

3.加includeSystemScope:本地可以运行,但是只要使用maven打包就不行,因为maven没有将本地的jar也打到生成的包中
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <!-- 作用:项目打成jar的同时将本地jar包也引入进去 -->
                <includeSystemScope>true</includeSystemScope>
            </configuration>
        </plugin>
    </plugins>
</build>

项目整合sdk最佳实践方案

sdk为公共模块,可在各个场景中使用,常见的公共模块使用场景和最佳实践:

  • 一方库:本工程中的各模块的相互依赖,比如微服务的公共模块;(sdk不适用此方案,sdk本来就是要提供给外部团队使用的)
  • 二方库:sdk给公司内部的其他团队使用;(可以使用nexus搭建企业自己的私有maven仓库,将sdk传到nexus私有仓库中供企业内部其他团队使用,nexus私有仓库搭建详见我的另外一篇文章《Nexus部署和使用(笔记)》 https://blog.csdn.net/ltx1472580369/article/details/113758564
  • 三方库:sdk给公司之外的第三方团队使用;(本文以上主要讲解的内容为此方案)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小绿豆

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值