文章目录
-
-
- 泛微OAe9-后端二开异步调用
-
- 案例一:同步调用SAP,生成SAP采购申请编号,再保存在流程里,保存成功后,再同步给OA人员发送消息,最后放行流程。
- 案例二:同步调用SAP,生成SAP采购申请编号,再保存在流程里,保存成功后直接放行流程,再后台异步给OA人员发送消息。
-
- [1 发送消息类:AsyncMessageAction.java](#1 发送消息类:AsyncMessageAction.java)
- [2 发送消息类:AsyncMessageAction.java](#2 发送消息类:AsyncMessageAction.java)
- 案例三:异步调用SAP,生成SAP采购申请编号,不保存在流程里;再异步给OA人员发送消息;再异步回调OMS传递流程数据。
-
- [1 业务回调分开编写](#1 业务回调分开编写)
- [2 acton类](#2 acton类)
-
泛微OAe9-后端二开异步调用
在泛微OA二开的action接口中,大多数情况下都是同步执行一些回调的逻辑,比如单纯的调用SAP,生成一些SAP采购申请编号,生成完成,并且保存在流程里后,流程才往下批准。这种情况流程的审批效率,高度依赖调用SAP的耗时,假如SAP系统异常,OA流程就永远批不下去,影响流程审批效率。如果回调其他的一些接口不需要等响应结果,流程可以先放行,后台异步执行其他的回调,回调失败可以记录在表里,可以定时扫描表对失败的请求发起重试。
下面实战几个真实的案例:
案例一:同步调用SAP,生成SAP采购申请编号,再保存在流程里,保存成功后,再同步给OA人员发送消息,最后放行流程。
假设:
1、调用SAP,生成SAP采购申请编号,再保存在流程里,耗时5秒;
2、OA人员发送消息,耗时3秒。
那么案例一从批准流程,到流程放行,实际耗时:5+3=8秒。
这种场景不需要代码举例,就是最常见的同步代码,依次把代码逻辑写在接口里即可。
案例二:同步调用SAP,生成SAP采购申请编号,再保存在流程里,保存成功后直接放行流程,再后台异步给OA人员发送消息。
假设:
1、调用SAP,生成SAP采购申请编号,再保存在流程里,耗时5秒;
2、OA人员发送消息,耗时3秒。
那么案例二从批准流程,到流程放行,实际耗时:5秒。因为OA人员发送消息是异步的,是异步执行。
1 发送消息类:AsyncMessageAction.java
java
public class AsyncMessageAction extends BaseCronJob {
private static final Logger logger = LoggerFactory.getLogger(AsyncMessageAction.class);
private static final int MESSAGE_TYPE = 132;
@Override
public void execute() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String todayStr = LocalDateTime.now().format(formatter);
// 发送给我本人
sendMessage(10795, todayStr, null, null);
}
/**
* 模拟发送消息提醒
* @param userid 通知人
* @param todayStr 日期
*/
private List<Object> sendMessage(int userid, String todayStr, String name, String url) {
// 标题
StringBuilder title = new StringBuilder();
title.append("异步消息推送");
Set<String> userSet = new HashSet();
userSet.add(String.valueOf(userid));
// 内容
StringBuilder context = new StringBuilder();
context.append("测试异步消息发送,时间:" + todayStr);
MessageBean messageBean = null;
List<Object> values = new ArrayList<>();
try {
messageBean = Util_Message.createMessage(MessageType.newInstance(MESSAGE_TYPE), userSet, title.toString(), context.toString(), url, url);
// 创建人id
messageBean.setCreater(1);
String messageId = messageBean.getMessageId();
boolean isTure = Util_Message.store(messageBean); // 发送
if (isTure) {
values.add(userid);
values.add(context.toString());
values.add(DateUtil.getCurrentDate() + " " + DateUtil.getCurrentHourMin());
}
return values;
} catch (IOException e) {
logger.error("AssetInventoryTimeoutReminder:通知盘点人发送消息提醒出错:" + e.toString());
e.printStackTrace();
return values;
}
}
}
2 发送消息类:AsyncMessageAction.java
java
/**
* @author:
* @date: 2025/5/13
*
* <p>1、研发组件/整机试制申请,业务类型为PCBA板卡时触发此接口 </p>
* <p>2、研发PCBA打样申请</p>
*/
public class ProcessOutsourcingOrderCreateTest implements Action {
private static final Log logger = LogFactory.getLog(ProcessOutsourcingOrderCreateTest.class);
private static final String SAP_FUNCTION_NAME = "ZOA_PRODUCTIONORDER_CREATE";
private static final String INPUT_TABLE = "T_ITEM";
private static final String RETURN_TABLE = "T_RETURN";
private static final String YF_PCBD = "ZP07";
private static final String GZ_PCBD = "ZP06";
private String formId;
// 共享线程池
private static final ExecutorService MESSAGE_EXECUTOR =
new ThreadPoolExecutor(
4,
8,
60L,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(500),
new ThreadPoolExecutor.AbortPolicy()
);
// 异步调用发送消息
private void sendMessageAsync() {
try {
MESSAGE_EXECUTOR.execute(() -> {
try {
new AsyncMessageAction().execute();
logger.info("异步消息发送任务执行完成");
} catch (Exception e) {
logger.error("异步消息发送失败", e);
}
});
} catch (RejectedExecutionException e) {
logger.error("异步消息任务提交失败,线程池队列已满", e);
}
}
@Override
public String execute(RequestInfo requestInfo) {
String loggerHead = ">>>" + WorkflowFunction.printWorkflowTraceInfo(requestInfo);
logger.info(loggerHead + " is starting...");
RequestManager requestManager = requestInfo.getRequestManager();
Map<String, String> mainTable = WorkflowFunction.getMainTable(requestInfo);
int detailIndex = -1;
if (Integer.parseInt(formId) == -1778) { // <研发组件/整机试制申请>
detailIndex = 1;
}
if (Integer.parseInt(formId) == -1949) { // 研发PCBA打样申请
detailIndex = 0;
}
try {
if (detailIndex == -1) {
throw new Exception("formid异常,请截图联系管理员.");
}
List<Map<String, String>> detailTable2 = WorkflowFunction.getDetailTable(requestInfo, detailIndex); // PCBA明细表
if (detailIndex == 1) {
String wlfl = mainTable.get("wlfl"); // 业务类型
if (!wlfl.equals("2")) {
return Action.SUCCESS; // 非 PCBA板卡,接口退出
}
}
String sfsyzfczzj = mainTable.get("sfsyzfczzj"); // 是否使用政府财政资金
String zfxmbm = mainTable.get("zfxmbm"); // 政府项目编码
String fkyxzh = mainTable.get("fkyxzh"); // 付款银行账号
String zfxmzy = mainTable.get("zfxmzy"); // 政府项目摘要
String fkbz = mainTable.get("fkbz"); // 付款备注
String liush = mainTable.get("liush"); // 流水号
String sfwgzpcba = mainTable.get("sfwgzpcba"); // 是否为工装PCBA
List<Map<String, Object>> sapItItem = new ArrayList<>();
Map<String, Object> rowData = null;
int index = 0; // 行号
for (Map<String, String> dt : detailTable2) { // 遍历构建SAP参数
rowData = new HashMap<>();
rowData.put("AUART", "0".equals(sfwgzpcba) ? GZ_PCBD : YF_PCBD); // 订单类型
rowData.put("ZZFXMBM", "0".equals(sfsyzfczzj) ? zfxmbm : ""); // 政府项目编码
rowData.put("ZFKYHZH", "0".equals(sfsyzfczzj) ? fkyxzh : ""); // 付款银行账号
rowData.put("ZZFXMZY", "0".equals(sfsyzfczzj) ? zfxmzy : ""); // 政府项目摘要
rowData.put("ZNOTES", "0".equals(sfsyzfczzj) ? fkbz : ""); // 付款备注
rowData.put("ZZLCBH", liush); // 流水号
rowData.put("CANUM", index); // 行号
rowData.put("MATNR", dt.get("yjwlbmllan")); // 样机物料编码(浏览按钮)
rowData.put("MENGE", dt.get("ylzs")); // 用量(整数)
rowData.put("ZYFXM", dt.get("yfnbddh")); // 研发内部订单号
rowData.put("ZBURN", dt.get("sfsl")); // 是否烧录
rowData.put("ZAGING", dt.get("sflh")); // 是否老化
rowData.put("ZTEST", dt.get("sfcs")); // 是否测试
rowData.put("ZBURNCHIP", dt.get("sfyslxp")); // 是否有烧录芯片
sapItItem.add(rowData);
index ++;
}
// 调用SAP
SapRemoteFunctionCaller srfc = new SapRemoteFunctionCaller(SAP_FUNCTION_NAME);
logger.info(srfc.setInputTable(INPUT_TABLE, sapItItem));
logger.info(srfc.setOutputTableNames(new String[]{RETURN_TABLE}));
logger.info(srfc.call());
Map<String, Object> result = srfc.getResult();
logger.info(result.toString());
List<Map<String, Object>> resultTable = (List<Map<String, Object>>) result.get(RETURN_TABLE);
Collections.sort(resultTable, Comparator.comparingInt(row -> Integer.parseInt(String.valueOf(row.get("CANUM"))))); // sap返回行数据按行号排序
List<Object> errorList = new ArrayList<>();
for (int i=0; i<resultTable.size(); i++) {
// SAP每一行都单独创建sap资产编号
if (!"S".equals(resultTable.get(i).get("E_CODE").toString())) {
errorList.add("第"+ (i+1) + "行错误:" +resultTable.get(i).get("E_MSG"));
continue;
}
// 返回值=S,则成功
detailTable2.get(i).put("sapcgsqdh", (String) resultTable.get(i).get("BANFN"));
}
if (errorList == null || errorList.isEmpty()) { // sap所有行采购申请单都成功
WorkflowFunction.saveDetailTable(requestInfo, detailTable2, new String[]{"sapcgsqdh"}, detailIndex);
// SAP成功且明细保存完成后,异步发送OA站内消息
sendMessageAsync();
return Action.SUCCESS;
}
throw new RuntimeException(errorList.toString());
} catch (Exception e) {
logger.info(loggerHead + " ProcessOutsourcingOrderCreate... error:" + e.toString());
requestManager.setMessagecontent("系统异常,请截图此信息联系管理员:" + e.getMessage());
return Action.FAILURE_AND_CONTINUE;
}
}
}
案例三:异步调用SAP,生成SAP采购申请编号,不保存在流程里;再异步给OA人员发送消息;再异步回调OMS传递流程数据。
1 业务回调分开编写
java
/**
* 异步调用 SAP
*/
private void executeSapAsync(RequestInfo requestInfo) {
BUSINESS_EXECUTOR.execute(() -> {
try {
processSap(requestInfo); // 具体逻辑自行实现
} catch (Exception e) {
logger.error("异步调用 SAP 失败", e);
}
});
}
/**
* 异步发送 OA 站内消息
*/
private void sendMessageAsync() {
BUSINESS_EXECUTOR.execute(() -> {
try {
sendMessage(requestInfo); // 具体逻辑自行实现
} catch (Exception e) {
logger.error("异步发送 OA 站内消息失败", e);
}
});
}
/**
* 异步调用 OMS
*/
private void executeOmsAsync(RequestInfo requestInfo) {
BUSINESS_EXECUTOR.execute(() -> {
try {
processOms(requestInfo); // 具体逻辑自行实现
} catch (Exception e) {
logger.error("异步调用 OMS 失败", e);
}
});
}
2 acton类
java
@Override
public String execute(RequestInfo requestInfo) {
// 异步调用 SAP
executeSapAsync(requestInfo);
// 异步发送 OA 站内消息
sendMessageAsync(requestInfo);
// 异步调用 OMS
executeOmsAsync(requestInfo);
// 三个任务提交后,Action 立即返回
return Action.SUCCESS;
}
假设:
1、调用SAP,生成SAP采购申请编号,耗时5秒;
2、OA人员发送消息,耗时3秒;
3、回调OMS传递流程数据,耗时10秒。
那么案例三从批准流程,到流程放行,实际耗时:10秒。取三次异步中,最长的那一次耗时。