如何用Java代码创建和执行调度计划和调度作业原创
金蝶云社区-吴锐雄
吴锐雄
28人赞赏了该文章 7780次浏览 未经作者许可,禁止转载编辑于2022年07月25日 22:44:33

创作不易,如果文章对您有帮助,请为我点击一个朴实无华的赞^_^


关键词:调度


一、需求

用java代码创建和执行调度计划和调度作业。


我并不推荐用代码去创建调度计划和调度作业,请开发者们尽量在【系统服务云】【系统管理】,

左侧边栏【调度管理】中,使用界面化的方式来创建调度计划和调度作业。


关于如何使用调度任务、调度计划、调度作业,请查看我的另一篇文章:

https://club.kdcloud.com/article/173120773756899840


二、思路与方案

1.创建动态表单页面,拖入几个工具栏的按钮

2.编写代码,创建和执行调度计划、调度作业

3.进入页面中,点击工具栏按钮,让代码中的调度计划开始执行



三、实现过程

1.创建单据页面,用来为第2步骤的插件提供点击事件

image.png

image.png


2.编写插件

关于创建调度作业有很多种方式,使用JobForm、JobDispatcherProxy、JobClient

下面使用JobForm或者JobDispatcherProxy创建调度作业和调度计划。

有开发者私信我提出疑问,为什么要在单据中使用调度作业,觉得并不符合实际场景。

在这里做一些解释,本文只是为了探讨调度作业和调度计划的使用方式,请各位开发者根据实际业务场景进行开发


创建调度作业

private JobInfo getJobInfo () {
    JobInfo jobInfo = new JobInfo();
    // 执行类所在的应用名
    jobInfo.setAppId("kdec_wrx_col_app");
    // 实时作业,即时执行
    // jobInfo.setJobType(JobType.REALTIME);
    // 业务作业,等到开始时间节点时才执行
    jobInfo.setJobType(JobType.BIZ);

    Date now = new Date();
    SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    // 设置调度作业名称yyyyMMddHHmmss
    jobInfo.setName("赋能部wrx插件作业_" + sf.format(now));
    // 设置调度作业编码
    jobInfo.setNumber("kdf_job_wrx_p_" + sf.format(now));

    // 随机产生一个JobId (任务目标的标识)
    /*String id = UUID.randomUUID().toString();
    jobInfo.setId(id);*/

    jobInfo.setTaskClassname("kd.bos.api.task.KDFLogTask");

    // 自定义参数
    Map<String,Object> params = new HashMap<>();
    params.put("time", 10);         // 自定义参数,示例任务执行循环次数,10次

    jobInfo.setParams(params);      // 回调参数,设置一个回调处理标识(actionId)
    return jobInfo;
}


创建调度计划

private PlanInfo getPlanInfo (JobInfo jobInfo) {
    PlanInfo planInfo = new PlanInfo();
    // 设置作业
    planInfo.setJobId(jobInfo.getId());
    SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    Date now = new Date();
    // 设置调度计划名称
    planInfo.setName("赋能部wrx插件计划_" + sf.format(now));
    // 设置调度计划编码
    planInfo.setNumber("kdf_plan_wrx_p_" + sf.format(now));

    // 设置开始时间结束时间
    Calendar startCalendar = Calendar.getInstance();
    // 开始时间为:当前时间1分钟之后
    startCalendar.setTime(new Date(now.getTime() + 1000 * 60 * 1));
    Calendar endCalendar = Calendar.getInstance();
    // 结束时间为:当前时间5分钟之后,整个调度计划执行时间为
    endCalendar.setTime(new Date(now.getTime() + 1000 * 60 * 5));
    planInfo.setStartTime(startCalendar);
    planInfo.setEndTime(endCalendar);

    // 设置重复模式,1分钟
    planInfo.setRepeatMode(RepeatModeEnum.ByMinutes);
    // 设置周期,1次
    // 周期+重复模式,表示这个调度计划为1分钟执行1次
    planInfo.setPeriod(1);

    return planInfo;
}


执行单次调度作业,不配置调度计划

@Override
public void itemClick(ItemClickEvent evt) {
    super.itemClick(evt);
    if (evt.getItemKey().equals("kdec_tool_job_c")) {
        // 直接执行一条调度作业,不设置调度计划
        JobInfo jobInfo = getJobInfo();
        CloseCallBack closeCallBack = new CloseCallBack(this, "taskcloseback");
        // 发布任务,并显示进度
        JobForm.dispatch(jobInfo, this.getView(), closeCallBack);
        System.out.println("JobId: " + jobInfo.getId());
    }
}

/**
  * 回调事件,在任务处理完毕后继续后续处理
  */
@Override
public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
    super.closedCallBack(closedCallBackEvent);
    if (StringUtils.equals(closedCallBackEvent.getActionId(), "taskcloseback")) {
        this.taskCallBack(closedCallBackEvent.getReturnData());
    }
}

private void taskCallBack(Object returnData) {
    if (returnData == null) {
        return;
    }
    if (returnData instanceof Map<?, ?>) {
        @SuppressWarnings("unchecked")
        Map<String, Object> result = (Map<String, Object>)returnData;
        if (result.containsKey("taskinfo")) {
            String taskInfoStr = (String)result.get("taskinfo");
            if (StringUtils.isNotBlank(taskInfoStr)) {
                TaskInfo taskInfo = SerializationUtils.fromJsonString(taskInfoStr, TaskInfo.class);

                if (taskInfo.isTaskEnd()) {
                    // 获取任务执行完毕,生成的内容
                    String data = taskInfo.getData();
                    Map map = SerializationUtils.fromJsonString(data, Map.class);
                    data = map.get(KDFLOGTASK_CON).toString();
                    this.getView().showMessage(data);
                }
            }
        }
    }
}


设置调度计划和调度作业

// 执行调度计划
JobDispatcherProxy proxy = new JobDispatcherProxy();
// 创建调度作业
JobInfo jobInfo = getJobInfo();
String jobId = proxy.dispatch(jobInfo);
// 创建调度计划
PlanInfo planInfo = getPlanInfo(jobInfo);
String planId = proxy.createPlan(planInfo);

System.out.println("JobId: " + jobId + ", Number= " + jobInfo.getNumber());
System.out.println("PlanId: " + planId + ", Number= " + planInfo.getNumber());
System.out.println("TaskId: " + jobInfo.getTaskId());

getView().showMessage("JobId: " + jobId + ", Number: " + jobInfo.getNumber() + "\n & " +
        "PlanId: " + planId + ", Number: " + planInfo.getNumber() + "\n & " +
        "TaskId: " + jobInfo.getTaskId());


删除调度作业

JobDispatcherProxy proxy = new JobDispatcherProxy();
boolean success = proxy.deleteJob(getModel().getValue("kdec_inputid").toString());
if (success) {
    System.out.println("删除调度作业成功");
}


删除调度计划

JobDispatcherProxy proxy = new JobDispatcherProxy();
boolean success = proxy.deletePlan(getModel().getValue("kdec_inputid").toString());
if (success) {
    System.out.println("删除调度计划成功");
}


查询调度作业

JobDispatcherProxy proxy = new JobDispatcherProxy();
TaskInfo taskInfo = proxy.queryTask(getModel().getValue("kdec_inputid").toString());
System.out.println("JobId: " + taskInfo.getJobId());


创建调度任务类

package kd.bos.api.task;

import kd.bos.context.RequestContext;
import kd.bos.exception.KDException;
import kd.bos.schedule.executor.AbstractTask;

import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;

public class KDFLogTask extends AbstractTask {

   private static final Log log = LogFactory.getLog(KDFLogTask.class);

   public static final String KDFLOGTASK_CON = "KDFLogTaskCallBackData";

   @Override
   public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
       Map<String, Object> resmap = new HashMap<>();
       if (map.get("time") instanceof Integer) {
           for (int i = 0; i < (Integer)map.get("time"); i++) {
               try {
                   SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
                   System.out.println("打印日志测试:" + df.format(new Date()));// new Date()为获取当前系统时间
                   log.info("打印日志测试:" + df.format(new Date()));
                   resmap.put(KDFLOGTASK_CON, "KDFLogTask execute success");
               } catch(Exception e) {
                   // 捕获到异常,反馈进度
                   feedbackProgress(i);
                   // 有异常就终止调度任务
                   if (isStop()) {
                       stop();
                   }
                   resmap.put(KDFLOGTASK_CON, "KDFLogTask execute fail");
               }
           }
       }
       feedbackCustomdata(resmap);
   }

}



进入页面中,点击工具栏按钮,让代码中的调度计划开始创建和执行

image.png


四、效果图

查看调度作业/调度计划的列表,调度作业的执行情况


image.png

image.png

image.png


五、开发环境版本

image.png


六、注意事项

开发过程中遇到的问题场景和解决方案:

调度任务传递参数发生改变

在开发过程中,如果用户选择业务模式启动调度计划,传递DynamicObject为参数,在调度任务中,DynamicObject会被转为JsonObject。

如果这时候不做参数判断,直接把JsonObject传入SaveServiceHelper中进行保存操作saveOpera方法调用之后,返回结果是保存失败的。

image.png

image.png


解决方案:把JsonObject构造成DynamicObject,或者用BusinessDataServiceHelper重新查一次。

image.png


七、参考资料

【开发平台】指导手册

学习成长中心

调度计划

苍穹界面化配置调度计划,调度作业

调度介绍





八、附件

附件包含补丁包和java源代码。

补丁包包含jar包和元数据包,请在mc中安装补丁包,如果是在开发平台里面直接导入,那么jar包不生效,需要复制代码,手动添加插件。

附件里的案例和本文的一些截图,在界面上略有差异,但实现方式是一致的。

插件文件:CreateJobPlanPlugIn.java,KDFLogTask.java已上传。







赞 28