Camunda JavaScript SDK:浏览器端流程交互
还在为前后端分离架构下的流程交互而烦恼?Camunda JavaScript SDK 为您提供了在浏览器端直接与 Camunda 流程引擎交互的能力,让前端开发者也能轻松处理业务流程任务。本文将深入解析 Camunda JavaScript SDK 的核心功能和使用方法,帮助您构建现代化的流程驱动应用。
读完本文您将获得
- ✅ Camunda JavaScript SDK 的完整架构解析
- ✅ 核心 API 的详细使用指南和代码示例
- ✅ 表单处理、任务管理的最佳实践
- ✅ 错误处理和本地存储的实用技巧
- ✅ 与后端流程引擎的无缝集成方案
Camunda JavaScript SDK 架构概览
Camunda JavaScript SDK 是一个专门为浏览器环境设计的客户端库,提供了与 Camunda 流程引擎 REST API 交互的完整解决方案。其核心架构采用模块化设计,主要包含以下几个关键组件:
核心 API 功能详解
1. 客户端初始化与配置
Camunda JavaScript SDK 的核心入口是 CamundaClient
类,它负责管理与流程引擎的连接和所有资源操作。
// 初始化 Camunda 客户端
const client = new CamSDK.Client({
apiUri: 'http://localhost:8080/engine-rest',
engine: 'default', // 可选,默认为 'default'
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token-here'
}
});
// 获取任务资源实例
const taskResource = client.resource('task');
2. 任务管理 API
任务管理是 SDK 的核心功能,支持任务的查询、领取、完成等完整生命周期操作。
查询任务列表
// 查询分配给当前用户的任务
taskResource.list({
assignee: 'current-user',
active: true,
sortBy: 'created',
sortOrder: 'desc',
firstResult: 0,
maxResults: 50
}, function(err, result) {
if (err) {
console.error('获取任务列表失败:', err);
return;
}
const tasks = result._embedded.task;
tasks.forEach(task => {
console.log(`任务ID: ${task.id}, 名称: ${task.name}, 创建时间: ${task.created}`);
});
});
完成任务
// 完成任务并更新流程变量
taskResource.complete({
id: 'task-123',
variables: {
approvalResult: {
value: 'approved',
type: 'String'
},
comment: {
value: '申请已审核通过',
type: 'String'
}
}
}, function(err, result) {
if (err) {
console.error('完成任务失败:', err);
return;
}
console.log('任务完成成功');
});
任务领取与释放
// 领取任务
taskResource.claim('task-123', 'user-456', function(err) {
if (err) {
console.error('领取任务失败:', err);
return;
}
console.log('任务领取成功');
});
// 释放任务
taskResource.unclaim('task-123', function(err) {
if (err) {
console.error('释放任务失败:', err);
return;
}
console.log('任务释放成功');
});
3. 表单处理功能
CamundaForm 类是专门为处理嵌入式表单设计的,提供了强大的表单渲染、数据绑定和提交功能。
表单初始化与渲染
// 初始化表单
const camForm = new CamSDK.Form({
client: client,
taskId: 'task-123',
containerElement: document.getElementById('form-container'),
formUrl: '/forms/approval-form.html'
});
// 监听表单事件
camForm.on('form-loaded', function() {
console.log('表单加载完成');
});
camForm.on('variables-applied', function() {
console.log('流程变量已应用到表单');
});
camForm.on('submit-success', function() {
console.log('表单提交成功');
alert('操作成功!');
});
表单提交与错误处理
// 提交表单
document.getElementById('submit-btn').addEventListener('click', function() {
camForm.submit(function(err, result) {
if (err) {
console.error('表单提交失败:', err);
alert('提交失败: ' + err.message);
return;
}
console.log('表单提交成功:', result);
});
});
// 报告BPMN错误
document.getElementById('error-btn').addEventListener('click', function() {
camForm.error('APPROVAL_REJECTED', '申请不符合政策要求', function(err) {
if (err) {
console.error('报告错误失败:', err);
return;
}
console.log('BPMN错误报告成功');
});
});
// 报告BPMN升级
document.getElementById('escalate-btn').addEventListener('click', function() {
camForm.escalate('MANAGER_APPROVAL_NEEDED', function(err) {
if (err) {
console.error('报告升级失败:', err);
return;
}
console.log('BPMN升级报告成功');
});
});
高级功能与最佳实践
1. 本地存储与数据持久化
CamundaForm 提供了自动的本地存储功能,确保用户在填写表单过程中不会因页面刷新而丢失数据。
// 手动保存表单状态
camForm.store(function(err) {
if (err) {
console.error('保存表单状态失败:', err);
return;
}
console.log('表单状态已保存到本地存储');
});
// 检查是否有可恢复的数据
if (camForm.isRestorable()) {
if (confirm('检测到未提交的表单数据,是否恢复?')) {
camForm.restore(function(err) {
if (err) {
console.error('恢复表单数据失败:', err);
return;
}
console.log('表单数据恢复成功');
});
}
}
// 清理过期的本地存储数据
CamSDK.Form.cleanLocalStorage(Date.now() - 24 * 60 * 60 * 1000); // 清理24小时前的数据
2. 文件上传处理
SDK 内置了文件上传功能,支持对上传文件的大小验证和自动转换。
<!-- HTML 表单中的文件上传字段 -->
<input type="file"
cam-variable-name="attachment"
cam-variable-type="File"
cam-max-filesize="10485760"
accept=".pdf,.doc,.docx">
// 文件上传的自动处理
camForm.on('variables-applied', function() {
const fileVariable = camForm.variableManager.variables['attachment'];
if (fileVariable && fileVariable.contentUrl) {
// 显示已上传的文件链接
const downloadLink = `<a href="${fileVariable.contentUrl}" target="_blank">下载附件</a>`;
document.getElementById('file-preview').innerHTML = downloadLink;
}
});
3. 自定义表单字段处理器
您可以扩展 SDK 的表单处理能力,添加自定义的字段类型处理器。
// 自定义颜色选择器字段处理器
const ColorPickerHandler = function(element, variableManager, form) {
this.element = $(element);
this.variableManager = variableManager;
this.form = form;
this.variableName = this.element.attr('cam-variable-name');
this.initialize();
};
ColorPickerHandler.prototype.initialize = function() {
const self = this;
// 初始化颜色选择器
this.element.colorPicker({
onChange: function(color) {
self.variableManager.setVariableValue(self.variableName, color);
}
});
};
ColorPickerHandler.prototype.applyValue = function() {
const value = this.variableManager.getVariableValue(this.variableName);
if (value) {
this.element.colorPicker('setColor', value);
}
};
ColorPickerHandler.prototype.getValue = function() {
const color = this.element.colorPicker('getColor');
this.variableManager.setVariableValue(this.variableName, color);
};
// 注册自定义处理器
const form = new CamSDK.Form({
client: client,
taskId: 'task-123',
formElement: document.getElementById('my-form'),
formFieldHandlers: [
CamSDK.form.fields.InputFieldHandler,
CamSDK.form.fields.ChoicesFieldHandler,
ColorPickerHandler, // 添加自定义处理器
CamSDK.form.fields.FileDownloadHandler
]
});
实战案例:审批流程集成
下面是一个完整的审批流程集成示例,展示了如何在实际项目中使用 Camunda JavaScript SDK。
class ApprovalWorkflow {
constructor(apiUrl, engineName) {
this.client = new CamSDK.Client({
apiUri: apiUrl,
engine: engineName || 'default'
});
this.taskResource = this.client.resource('task');
}
// 获取用户待办任务
async getUserTasks(userId, filters = {}) {
return new Promise((resolve, reject) => {
const params = {
assignee: userId,
active: true,
...filters
};
this.taskResource.list(params, (err, result) => {
if (err) return reject(err);
resolve(result._embedded.task || []);
});
});
}
// 初始化任务表单
initTaskForm(taskId, containerId) {
return new CamSDK.Form({
client: this.client,
taskId: taskId,
containerElement: document.getElementById(containerId)
});
}
// 提交审批结果
async submitApproval(taskId, decision, comment) {
return new Promise((resolve, reject) => {
this.taskResource.complete({
id: taskId,
variables: {
approvalDecision: {
value: decision,
type: 'String'
},
approvalComment: {
value: comment,
type: 'String'
}
}
}, (err, result) => {
if (err) return reject(err);
resolve(result);
});
});
}
// 监听任务事件
setupTaskEventListeners(form) {
form.on('form-loaded', () => this.onFormLoaded());
form.on('variables-fetched', () => this.onVariablesFetched());
form.on('submit-success', (result) => this.onSubmitSuccess(result));
form.on('submit-failed', (error) => this.onSubmitFailed(error));
}
onFormLoaded() {
console.log('审批表单加载完成');
this.showLoading(false);
}
onVariablesFetched() {
console.log('流程变量获取完成');
this.updateUIWithVariables();
}
onSubmitSuccess(result) {
console.log('审批提交成功', result);
alert('审批操作已完成!');
this.redirectToTaskList();
}
onSubmitFailed(error) {
console.error('审批提交失败', error);
alert('提交失败: ' + error.message);
}
// UI 相关方法
showLoading(show) {
document.getElementById('loading').style.display = show ? 'block' : 'none';
}
updateUIWithVariables() {
// 根据流程变量更新UI显示
}
redirectToTaskList() {
window.location.href = '/tasks';
}
}
// 使用示例
const workflow = new ApprovalWorkflow('http://localhost:8080/engine-rest');
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', async () => {
try {
const tasks = await workflow.getUserTasks('current-user-id');
if (tasks.length > 0) {
const form = workflow.initTaskForm(tasks[0].id, 'form-container');
workflow.setupTaskEventListeners(form);
}
} catch (error) {
console.error('初始化失败:', error);
}
});
性能优化与错误处理
1. 请求优化策略
// 配置HTTP客户端优化
const client = new CamSDK.Client({
apiUri: 'http://localhost:8080/engine-rest',
resources: {
task: {
timeout: 30000, // 30秒超时
retry: {
attempts: 3,
delay: 1000
}
}
}
});
// 批量操作减少请求次数
async function batchCompleteTasks(taskIds, variables) {
const promises = taskIds.map(taskId => {
return new Promise((resolve, reject) => {
client.resource('task').complete({
id: taskId,
variables: variables
}, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
});
return Promise.all(promises);
}
2. 错误处理与重试机制
class ResilientCamundaClient {
constructor(baseConfig) {
this.client = new CamSDK.Client(baseConfig);
this.retryConfig = {
maxAttempts: 3,
retryDelay: 1000,
retryableErrors: ['ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT']
};
}
async withRetry(operation, ...args) {
let lastError;
for (let attempt = 1; attempt <= this.retryConfig.maxAttempts; attempt++) {
try {
return await new Promise((resolve, reject) => {
operation(...args, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
} catch (error) {
lastError = error;
if (attempt === this.retryConfig.maxAttempts) {
break;
}
if (!this.isRetryableError(error)) {
break;
}
console.warn(`操作失败,第${attempt}次重试...`, error);
await this.delay(this.retryConfig.retryDelay * attempt);
}
}
throw lastError;
}
isRetryableError(error) {
return this.retryConfig.retryableErrors.some(code =>
error.code === code || error.message.includes(code)
);
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 包装常用方法
async listTasks(params) {
return this.withRetry(
this.client.resource('task').list.bind(this.client.resource('task')),
params
);
}
async completeTask(taskId, variables) {
return this.withRetry(
this.client.resource('task').complete.bind(this.client.resource('task')),
{ id: taskId, variables }
);
}
}
总结与展望
Camunda JavaScript SDK 为前端开发者提供了强大的流程交互能力,使得在浏览器环境中处理复杂的业务流程成为可能。通过本文的详细解析,您应该已经掌握了:
- 核心架构理解:深入了解 SDK 的模块化设计和组件关系
- API 熟练使用:掌握任务管理、表单处理等核心功能的调用方式
- 高级功能应用:学会使用本地存储、文件处理、自定义扩展等高级特性
- 实战开发技能:通过完整案例了解在实际项目中的集成方法
- 性能优化策略:掌握错误处理和性能优化的最佳实践
随着前端技术的不断发展,Camunda JavaScript SDK 将继续演进,为构建更加现代化、响应式的流程驱动应用提供强大支持。建议在实际项目中逐步应用这些技术,根据具体需求进行定制和优化,从而充分发挥 Camunda 流程引擎的强大能力。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考