# Action开发和定时任务开发

# 计划任务-定时任务

# 介绍

计划任务用来用户在e-cology系统自由定义一些需要定时执行的操作,它是由Quartz这一个开源的作业调度框架来实现;通过配置调度时间和自行开发调度动作来实现需要定时执行的任务。在开发时需要实现e-cology提供的自定义动作接口。

# 应用场景以及使用方法

# 应用场景

当我们业务中需要定时去跑数据或者需要定时执行某些业务逻辑时,即可以使用到定时任务,比如与第三方数据同步(推送数据或拉取数据)等

# 使用方法

在系统后台中有集成中心,找到计划任务后可以新创建计划任务,然后会有创建指引和说明

image-20231224115515273

新建计划任务卡片中需要填写计划任务标识和计划任务类,同时需要配置好对应的定时时间,使用的是Cron表达式

image-20231224115806451

定时任务说明 1、按照设定的时间定时执行任务,计划任务标识不能重复 2、计划任务类必须是类的全名,该类必须继承weaver.interfaces.schedule.BaseCronJob类,重写方法public void execute() {} 3、时间格式按Cron表达式的定义

# 代码示例

我们编写一个定时任务,该定时任务有两个参数,接下来使用代码来编写一个定时任务

package weaver.schedule.example;

import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import weaver.interfaces.schedule.BaseCronJob;

/**
 * <h1>测试定时任务dome</h1>
 * </br>
 * <p>create: 2023/12/24 12:02</p>
 *
 * <p></p>
 *
 * @author youHong.ai
 */
@Setter
@Getter
public class DomeTestCronJob extends BaseCronJob {

	/** 定时任务参数,只能使用string类型来接受 */
	private String testParam;

	private static final Logger logger = LoggerFactory.getLogger("cus");

	@Override
	public void execute() {
		// 使用基类的方法获取cron表达式
		String cronExpr = getCronExpr();
		logger.info(this.getClass().getName() + " start..... CronExpr: " + cronExpr + " testParam: " + testParam);
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

我们在WEB-INF/log4jinit.properties中加入cus的日志配置信息

image-20231224121710462

编译成功后打包到服务器,并且修改对应的log4jinit.properties文件重启后我们可以配置定时任务并且手动执行测试是否能够正常运转

image-20231224122852231

image-20231224122923672

配置完成后,我们可以进行手动执行,之后可以查看日志ecology/log/cus/cus.log日志,或者登录系统管理员账号在前端查看日志/log/cus/cus.log

image-20231224123356380

从日志中我们能看出,定时任务执行了,并且传递的参数也正常解析到了

# debug

这里的debug代码有多重形式,一种是使用本地单元测试进行debug,另外一种是使用idea远程debug,当然如果开发环境搭建的时候采用的其他的搭建形式,启动应用程序是从idea启动的,则debug就简单很多

本地单元测试

本地单元测试之前文档中有提及,在开发环境搭建中有讲过,必要的两个设置

// 设置服务名称,这里的名称也可以理解为数据源,默认是ecology
		GCONST.setServerName("ecology");
		// 设置根路径,这里设置的是服务的路径地址,如果没有吧WEB-INF文件放到项目中,则这里可以填写实际的ecology的路径地址
		GCONST.setRootPath("/your_path/src/main/resources/");
1
2
3
4

同时我们创建两个一个单元测试的基类,加入了before方法和注解

package e9dev.dome.envtest;

import com.alibaba.fastjson.JSON;
import org.junit.Before;
import weaver.general.GCONST;
import weaver.hrm.User;

/**
 * <h1>环境检测</h1>
 * </br>
 * <p>create: 2023/12/22 11:22</p>
 *
 * <p></p>
 *
 * @author youHong.ai
 */
public class E9BaseTest {
	public static void main(String[] args) {
		// 设置服务名称,这里的名称也可以理解为数据源,默认是ecology
		GCONST.setServerName("ecology");
		// 设置根路径,这里设置的是服务的路径地址,如果没有吧WEB-INF文件放到项目中,则这里可以填写实际的ecology的路径地址
		GCONST.setRootPath("/Users/aoey.oct.22/code/dome/e9-dev-demo/src/main/resources/");
		User user = new User(1);
		System.out.println(JSON.toJSONString(user));
	}
	/**
	 * ************************************************************
	 * <h2>针对后期使用单元测试,我们可以将路径地址写到before中这样就不用每次都重新设置和编写了</h2>
	 * <i>2023/12/22 11:37</i>
	 *
	 * @author youHong.ai
	 * ************************************************************
	 */

	@Before
	public void before(){

		// 设置服务名称,这里的名称也可以理解为数据源,默认是ecology
		GCONST.setServerName("ecology");
		// 设置根路径,这里设置的是服务的路径地址,如果没有吧WEB-INF文件放到项目中,则这里可以填写实际的ecology的路径地址
		GCONST.setRootPath("/Users/aoey.oct.22/code/dome/e9-dev-demo/src/main/resources/");
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

之后的单元测试,我们就可以继承E9BaseTest来进行单元测试

package e9dev.dome.envtest;

import org.junit.Test;
import weaver.schedule.example.DomeTestCronJob;

/**
 * <h1>单元测试</h1>
 * </br>
 * <p>create: 2023/12/24 12:39</p>
 *
 * <p></p>
 *
 * @author youHong.ai
 */
public class ActionAndCronJobTest extends E9BaseTest {


	@Test
	public void testCronJob() {
		DomeTestCronJob cronJob = new DomeTestCronJob();
		cronJob.setTestParam("单元测试参数");
		cronJob.execute();
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

如果采用远程debug,那么需要再服务端修改启动参数,这里以Resin为例,我们需要修改Resin4/conf/resin.properties中的jvm_args参数,在参数中添加-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${port}远程debug参数

image-20231224125338134

之后重启服务,在idea中配置如下

image-20231224125405552

image-20231224125444406

image-20231224125557946

好了,接下来就可以进行远程debug了,我们debug的形式运行我们配置的远程debug

image-20231224125740827

运行成功后,我们可以到前台进行手动执行,让请求进入我们的方法

image-20231224125825894

image-20231224131406465

可以看到我们成功debug(断点出现偏差是因为本地代码与服务器代码不一致导致的)

# 流程Action

流程action开发是我们在对流程开发中最为常见的开发,也是整个开发需求中最多的开发类型

# 节点附加操作执行顺序

保存表单数据——>节点后附加操作——>生成编号——>出口附加规则——>节点前附加操作——>插入操作者和签字意见

注:流程存为文档(workflowToDoc)接口特殊处理,作为流程提交的最后一个action执行

image-20231224131641087

# 使用action

使用action和使用定时任务一样,需要配置类的全路径类名,只是他的集成方式有多个入口,一个就是如同定时任务一样,在集成中心新建action

image-20231224141518412

image-20231224141532274

第二种方法可以在在流程路径设置(节点信息或者图形编辑)中直接绑定

image-20231224141614060

image-20231224141702167

# action编程说明

1.在节点前后附加操作中可设置接口动作,完成流程自定义附加操作 2.接口动作标识不能重复;接口动作类文件必须是类全名,该类必须实现接口weaver.interfaces.workflow.action.Action方法public String execute(RequestInfo request)

Action接口代码

package weaver.interfaces.workflow.action;

import weaver.soa.workflow.request.RequestInfo;

public interface Action {
  
    public static final String SUCCESS="1";
    
    /**
     * 失败信息,返回此信息,如果是节点前附加操作,将会阻止流程提交
     */
    public static final String FAILURE_AND_CONTINUE = "0";
    
    public String execute(RequestInfo request);
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

代码示例

package weaver.action.example;

import lombok.Getter;
import lombok.Setter;
import weaver.general.Util;
import weaver.hrm.User;
import weaver.interfaces.datasource.DataSource;
import weaver.interfaces.workflow.action.Action;
import weaver.soa.workflow.request.*;
import weaver.workflow.request.RequestManager;
import weaver.workflow.workflow.WorkflowBillComInfo;
import weaver.workflow.workflow.WorkflowComInfo;

/**
 * <h1>测试action</h1>
 * </br>
 * <p>create: 2023/12/24 14:18</p>
 *
 * <p></p>
 *
 * @author youHong.ai
 */
@Getter
@Setter
public class DomeTestAction implements Action {

	//action中定义属性,接收参数值,如参数值不为数据源,则注入的值为设置的String对象
	private String testParam = "";

	//action中定义属性,接收参数值,参数值为数据源,则注入的为DataSource对象
	private DataSource dataSource = null;

	@Override
	public String execute(RequestInfo requestInfo) {
		// 获取流程数据管理对象
		RequestManager requestManager = requestInfo.getRequestManager();
		// 获取流程表单名称
		String billTable = requestManager.getBillTableName();
		// 当前流程的requestId 唯一标识
		String requestId = requestInfo.getRequestid();
		// 当前流程节点的提交人
		User user = requestInfo.getRequestManager().getUser();
		// 当前流程的路径id
		int workflowId = requestManager.getWorkflowid();
		//        操作类型 submit - 提交  reject - 退回 等
		String src = requestManager.getSrc();
		// 如果表名获取不到,可以通过下面的方式再次尝试获取
		if ("".equals(billTable)) {
			WorkflowComInfo workflowComInfo = new WorkflowComInfo();
			String formId = workflowComInfo.getFormId(String.valueOf(workflowId));
			WorkflowBillComInfo workflowBillComInfo = new WorkflowBillComInfo();
			billTable = workflowBillComInfo.getTablename(formId);
		}
		int billId = requestManager.getBillid();//表单数据ID
		String requestName = requestManager.getRequestname();//请求标题
		String remark = requestManager.getRemark();//当前用户提交时的签字意见
		int formId = requestManager.getFormid();//表单ID
		int isBill = requestManager.getIsbill();//是否是自定义表单
		//取主表数据
		Property[] properties = requestInfo.getMainTableInfo().getProperty();// 获取表单主字段信息
		for (Property property : properties) {
			String name = property.getName();// 主字段名称
			String value = Util.null2String(property.getValue());// 主字段对应的值
		}
		//取明细数据
		DetailTable[] detailTable = requestInfo.getDetailTableInfo().getDetailTable();// 获取所有明细表
		if (detailTable.length > 0) {
			// 指定明细表
			for (DetailTable dt : detailTable) {
				Row[] s = dt.getRow();// 当前明细表的所有数据,按行存储
				// 指定行
				for (Row r : s) {
					Cell[] c = r.getCell();// 每行数据再按列存储
					// 指定列
					for (Cell c1 : c) {
						String name = c1.getName();// 明细字段名称
						String value = c1.getValue();// 明细字段的值
					}
				}
			}
		}
		//控制流程流转,增加以下两行,流程不会向下流转,表单上显示返回的自定义错误信息
		requestManager.setMessagecontent("返回自定义的错误信息");
		requestManager.setMessageid("错误信息编号");

		// return返回固定返回`SUCCESS`,
		// 当return `FAILURE_AND_CONTINUE`时,表单上会提示附加操作失败
		return SUCCESS;
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
常量 说明
SUCCESS "1" 成功标识,继续流程提交或执行下一个附加操作
FAILURE_AND_CONTINUE "0" 失败标识,阻断流程提交

# Action参数使用方式

使用自定义接口时,可以进行参数设置,和指定参数值。

设置后,需在action中实现对应的setter方法,oa会自动将设置的参数值注入

如果参数值为数据源,则注入的为DataSource对象,参数值为集成中设置的数据源名称

如参数值不为数据源,则注入的值为设置的String对象

public class TestMsgAction implements Action {

    //action中定义属性,接收参数值,如参数值不为数据源,则注入的值为设置的String对象
    private String aaa = "";

    //action中定义属性,接收参数值,参数值为数据源,则注入的为DataSource对象
    private DataSource bbb = null;

    //设置对应的stter方法
    public void setAaa(String aaa) {
        this.aaa = aaa;
    }

    //设置对应的stter方法
    public void setBbb(DataSource bbb) {
        this.bbb = bbb;
    }

    @Override
    public String execute(RequestInfo request) {
        return SUCCESS;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Action能做的事情

1、获取流程相关信息(requestid、workflowid、formid、isbill、表单信息等);

2、执行sql语句,查询或更新OA系统中的数据;

3、返回失败标识和提示信息,阻断前台流程提交,并显示提示信息;

4、强制收回触发action回滚

5、调用第三方系统的接口

6、实现自定义操作者

1、获取流程相关信息

public String execute(RequestInfo info) {
      //获取工作流id
      String workflowId = info.getWorkflowid(); 
      //获取流程id
      String requestid = info.getRequestid();
      //获取RequestManager对象
      RequestManager RequestManager = info.getRequestManager();
      //获取当前节点id
      int currentnodeid = RequestManager.getNodeid();
      //下一个节点id
      int nextnodeid = RequestManager.getNextNodeid();
      //获取流程表单id
      int formid = RequestManager.getFormid();
      //是否为单据
      int isbill = RequestManager.getIsbill();
      //获取数据库主表名
      String tableName = isbill == 1 ? "workflow_form" : RequestManager.getBillTableName();
      return Action.SUCCESS;
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

2、执行sql语句,查询或更新OA系统中的数据;

public class SQLExecuteActionDemo implements Action {
    @Override
    public String execute(RequestInfo info) {
        //获取流程id
        String requestid = info.getRequestid();

        /*************1.不带事务执行SQL开始***************/
        RecordSet rs = new RecordSet();
        //执行查询语句,查询数据
        rs.executeQuery("select testFieldName from formtable_main_45 where requestid = ?", requestid);
        if(rs.next()){
            String testFieldValue = rs.getString(1);
            new BaseBean().writeLog("testFieldName 的值是 :" + testFieldValue);
        }

        //执行update语句,更新数据
        rs.executeUpdate("update formtable_main_45 set testFieldName = ? where requestid = ?", "testValue", requestid);
        /*************1.不带事务执行SQL结束***************/


        /*************2.带事务执行SQL开始***************/
        RecordSetTrans rst = new RecordSetTrans();
        rst.setAutoCommit(false);
        try {
            rst.executeUpdate("update formtable_main_45 set testFieldName1 = ? where requestid = ?", "testValue1", requestid);

            rst.executeUpdate("update formtable_main_45 set testFieldName2 = ? where requestid = ?", "testValue2", requestid);

            //手动提交事务
            rst.commit();
        } catch (Exception e) {
            //执行失败,回滚数据
            rst.rollback();
            e.printStackTrace();
        }
        /*************2.带事务执行SQL结束***************/


        /*************3.查询或操作流程流转相关表开始***************/
        /*************此处需注意不要将RecordSetTrans对象的事务提交掉***************/
        RecordSetTrans requestRst = info.getRequestManager().getRsTrans();

        try {
            requestRst.executeQuery("select status from workflow_requestbase where requestid = ?", requestid);
            if (requestRst.next()) {
                String statusValue = rs.getString("status");
                new BaseBean().writeLog("statusValue 的值是 :" + statusValue);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        /*************3.查询或操作流程流转相关表结束***************/


        return Action.SUCCESS;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

注意点

  • 操作OA数据库中数据,必须使用OA自带的数据库操作类(推荐Recordet、RecordSetTrans),使用其他方式操作数据库,可能会出现数据库缓存读取不到最新数据的情况

  • 使用requestInfo.getRequestManager().getRsTrans()获取到的RecordSetTrans对象,不要手动提交或者回滚数据,会导致流程提交错误。

3、返回失败标识和提示信息,阻断前台流程提交,并显示提示信息;

    public String execute(RequestInfo request) {

        //获取requestId
        String requestId = request.getRequestid();

        float amount = 0;

        /*************1.直接查询数据库获取表单值***************/
        RecordSet rs = new RecordSet();
        rs.executeQuery("select amount from formtable_main_16 where requestid = ?", requestId);
        //获取金额字段的值
        if (rs.next()) {
            amount = rs.getFloat(1);
        }

        /*************2.直接查询数据库获取表单值***************/
        //获取主表数据
        Map<String, String> mainDatas = new HashMap<>();
        Property[] properties = request.getMainTableInfo().getProperty();
        for (Property propertie : properties) {
            mainDatas.put(propertie.getName(), propertie.getValue());
        }
        amount = Util.getFloatValue(Util.null2String(mainDatas.get("amount")));


        //金额字段值大于10000,阻断流程提交
        if(amount > 10000) {
            RequestManager requestManager = request.getRequestManager();
            requestManager.setMessagecontent("不允许提交金额大于10000的流程");
            return FAILURE_AND_CONTINUE;
        }

        return SUCCESS;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

4、强制收回触发action回滚

public String execute(RequestInfo request) {

        //获取requestId
        String requestId = request.getRequestid();

        //对应节点强制收回,则回滚数据
        if (request.getRequestManager().getNodeid() == 123) {
            RecordSet rs = new RecordSet();
            rs.executeUpdate("delete from uf_fix_log where requestid = ?", requestId);
        }

        return SUCCESS;
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14

注意

  • 所有节点执行强制收回或者删除都会执行,需在action中判断当前节点Id

5、调用第三方系统的接口

package weaver.interfaces.workflow.action.actionDemo;


import com.alibaba.fastjson.JSONObject;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import weaver.interfaces.workflow.action.Action;
import weaver.soa.workflow.request.Property;
import weaver.soa.workflow.request.RequestInfo;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class HttpTestAction implements Action {
    @Override
    public String execute(RequestInfo requestInfo) {

        //打印日志对象
        BaseBean baseBean = new BaseBean();
        baseBean.writeLog("获取到归属地action执行 requestid = " + requestInfo.getRequestid());

        Map<String, String> mainTableDatas = new HashMap<>();

        //获取主表字段数据
        Property[] properties = requestInfo.getMainTableInfo().getProperty();
        for(Property property : properties) {
            mainTableDatas.put(property.getName(), property.getValue());
        }

        String url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?";
        String result = httpUtil(url, "tel=" + mainTableDatas.get("dhhm"));

        String results[] = result.split("=");
        if(result.length() > 1) {
            JSONObject object = JSONObject.parseObject(results[1]);
            //获取到归属地
            String carrier = (String)object.get("carrier");
            baseBean.writeLog("获取到归属地 :" + carrier);
            RecordSet rs = new RecordSet();
            String sql = "update formtable_main_199 set gsd = ? where requestid = ?";
            rs.executeUpdate(sql, carrier, requestInfo.getRequestid());
        }

        return SUCCESS;
    }

    public String httpUtil(String path, String data) {
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(path);
            //打开url的连接
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            //设置请求方式
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);

            PrintWriter out = new PrintWriter(conn.getOutputStream());
            //发送请求参数
            out.print(data);
            out.flush();
            //获取响应输入流
            InputStream is = conn.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "GBK"));
            String str = "";
            while ((str = br.readLine()) != null) {
                result.append(str);
            }
            //关闭输入流
            is.close();
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result.toString();
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

6、实现自定义操作者

需实现weaver.interfaces.workflow.action.OperatorAction接口

package weaver.interfaces.workflow.action;

import java.util.List;

import weaver.soa.workflow.request.RequestInfo;


/**
 * 流程节点操作者自定义接口
 * @author Mcr
 *
 */
public interface OperatorAction {
	
	/**
	 * 取节点操作者,返回人员id集合
	 * @param requestInfo
	 * @return
	 */
	public List<String> execute(RequestInfo requestInfo);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

示例代码:

package weaver.interfaces.workflow.action.actionDemo;

import weaver.interfaces.workflow.action.OperatorAction;
import weaver.soa.workflow.request.RequestInfo;

import java.util.ArrayList;
import java.util.List;

public class OperatorActionTest implements OperatorAction {
    /**
     * 取节点操作者,返回人员id集合
     *
     * @param requestInfo
     * @return
     */
    @Override
    public List<String> execute(RequestInfo requestInfo) {

        List<String> operatorList = new ArrayList<>();

        //返回人员id
        operatorList.add("21");
        operatorList.add("22");

        return operatorList;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 建模扩展页面Action

建模扩展页面的Action在日常开发中比较少见,但是也是存在类似的需求,它的开发与流程的Action类似。

在对建模数据进行操作时候,可以触发自定义的接口动作,可以处理一些特殊的业务,比如对建模中的数据进行运算,或者把建模数据写入其他应用模块,或者写入第三方系统

# 使用建模扩展页面Action

找到对应建模的模块,然后找到页面扩展,对需要进行扩展拦截的按钮进行编辑加上action

image-20231224151217566

image-20231224151314915

image-20231224151343795

注意

  • 接口需要继承weaver.formmode.customjavacode.AbstractModeExpandJavaCodeNew

示例实现

package weaver.formmode.example;

import java.util.HashMap;
import java.util.Map;

import weaver.formmode.customjavacode.AbstractModeExpandJavaCodeNew;
import weaver.general.Util;
import weaver.hrm.User;
import weaver.soa.workflow.request.RequestInfo;/**
 * <h1>测试建模action</h1>
 * </br>
 * <p>create: 2023/12/24 15:21</p>
 *
 * <p></p>
 *
 * @author youHong.ai
 */
public  class DomeTestFormMode extends AbstractModeExpandJavaCodeNew {

	/**
	 * 执行模块扩展动作
	 * @param param
	 *  param包含(但不限于)以下数据
	 *  user 当前用户
	 *  importtype 导入方式(仅在批量导入的接口动作会传输) 1 追加,2覆盖,3更新,获取方式(int)param.get("importtype")
	 *  导入链接中拼接的特殊参数(仅在批量导入的接口动作会传输),比如a=1,可通过param.get("a")获取参数值
	 *  页面链接拼接的参数,比如b=2,可以通过param.get("b")来获取参数
	 * @return
	 */
	@Override
	public  Map<String, String> doModeExpand(Map<String, Object> param) {
		Map<String, String> result = new HashMap<String, String>();
		try {
			User user = (User)param.get("user");
			int billid = -1;//数据id
			int modeid = -1;//模块id
			RequestInfo requestInfo = (RequestInfo)param.get("RequestInfo");
			if(requestInfo!=null){
				billid = Util.getIntValue(requestInfo.getRequestid());
				modeid = Util.getIntValue(requestInfo.getWorkflowid());
				if(billid>0&&modeid>0){
					//------请在下面编写业务逻辑代码------
				}
			}
		} catch (Exception e) {
			result.put("errmsg","自定义出错信息");
			result.put("flag", "false");
		}
		return result;
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

注意:这里的RequestInfo和流程的RequestInfo是有一定的差异的,开发时,要更具实际情况来

点击保存时,回执行对应操作的action代码

image-20231224151933545

# 拓展点

添加的参数是如何赋值到成员变量的呢?

主要是利用反射的原理来实现的,如右侧的代码示例

Class clazz = Class.forName(classpath);
BaseCronJob basecj = (BaseCronJob) clazz.newInstance();
//参数加入
if (schedtlmap.get(id) != null) {
   Map<String, Object> m = (Map) schedtlmap.get(id);
   Set<String> keyset = m.keySet();
   for (String k : keyset) {
        try {
                Field f = clazz.getDeclaredField(k);
                f.setAccessible(true);
                f.set(basecj, m.get(k));
        } catch (Exception e) {
               e.printStackTrace();
               continue;
         }
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
二开文档   |