如何将Activiti REST返回的JSON转换为HTML表单?
我之前在做Activiti相关项目时也碰到过这个问题——它的REST接口返回的表单结构确实有自己的特殊性,通用的JSON转表单工具基本都没法直接适配,毕竟这些工具大多针对标准JSON Schema,而Activiti的返回里带了readable、writable、enumValues这类专属属性。不过其实自己实现转换逻辑并没有想象中难,下面分享几个我亲测可行的方案:
方案一:前端原生JavaScript手动转换
这是最直接的方式,直接遍历返回的formProperties数组,根据每个字段的type生成对应的HTML表单控件,同时处理必填、读写权限等属性。
function convertActivitiFormToHtml(formData) { // 创建表单容器 const form = document.createElement('form'); form.action = formData.taskUrl; form.method = 'POST'; form.className = 'activiti-form'; // 遍历每个表单属性 formData.formProperties.forEach(prop => { // 跳过不可读的字段 if (!prop.readable) return; const fieldWrapper = document.createElement('div'); fieldWrapper.className = 'form-field'; // 生成标签 const label = document.createElement('label'); label.htmlFor = prop.id; label.textContent = `${prop.name}${prop.required ? ' *' : ''}`; fieldWrapper.appendChild(label); let inputElement; // 根据字段类型生成对应控件 switch (prop.type) { case 'string': inputElement = document.createElement('input'); inputElement.type = 'text'; break; case 'date': inputElement = document.createElement('input'); inputElement.type = 'date'; // 如果需要适配Activiti的日期格式(比如dd/MM/yyyy),可以搭配flatpickr这类日期插件处理 inputElement.dataset.datePattern = prop.datePattern; break; case 'enum': inputElement = document.createElement('select'); // 非必填字段添加空选项 if (!prop.required) { const emptyOpt = document.createElement('option'); emptyOpt.value = ''; emptyOpt.textContent = '-- 请选择 --'; inputElement.appendChild(emptyOpt); } // 添加枚举选项 prop.enumValues.forEach(enumItem => { const opt = document.createElement('option'); opt.value = enumItem.id; opt.textContent = enumItem.name; inputElement.appendChild(opt); }); break; // 可以扩展支持boolean等其他类型 default: inputElement = document.createElement('input'); inputElement.type = 'text'; } // 设置控件基础属性 inputElement.id = prop.id; inputElement.name = prop.id; inputElement.value = prop.value || ''; inputElement.required = prop.required; // 不可写字段设置为禁用状态 if (!prop.writable) inputElement.disabled = true; fieldWrapper.appendChild(inputElement); form.appendChild(fieldWrapper); }); // 添加提交按钮 const submitBtn = document.createElement('button'); submitBtn.type = 'submit'; submitBtn.textContent = '提交表单'; form.appendChild(submitBtn); return form; } // 使用示例:假设已获取到Activiti返回的JSON数据 const activitiFormJson = { /* 你的JSON数据 */ }; const generatedForm = convertActivitiFormToHtml(activitiFormJson); document.body.appendChild(generatedForm);
这段代码的优势是灵活可控,完全适配Activiti的字段属性,不需要依赖第三方库,适合纯前端项目快速实现。
方案二:后端模板引擎渲染(Java项目适用)
如果你的项目是Java后端主导,可以在后端接收Activiti的REST返回后,用模板引擎(比如Thymeleaf、Freemarker)来渲染HTML表单,这样还能在后端统一处理日期格式转换等逻辑。
以Thymeleaf为例,模板片段如下:
<form th:action="${formData.taskUrl}" method="post" class="activiti-form"> <div th:each="prop : ${formData.formProperties}" th:if="${prop.readable}" class="form-field"> <label th:for="${prop.id}" th:text="${prop.name + (prop.required ? ' *' : '')}"> </label> <!-- 字符串类型字段 --> <input th:if="${prop.type == 'string'}" th:id="${prop.id}" th:name="${prop.id}" th:value="${prop.value}" th:required="${prop.required}" th:disabled="${!prop.writable}" type="text" /> <!-- 日期类型字段 --> <input th:if="${prop.type == 'date'}" th:id="${prop.id}" th:name="${prop.id}" th:value="${#dates.format(prop.value, prop.datePattern)}" th:required="${prop.required}" th:disabled="${!prop.writable}" type="date" /> <!-- 枚举类型字段 --> <select th:if="${prop.type == 'enum'}" th:id="${prop.id}" th:name="${prop.id}" th:required="${prop.required}" th:disabled="${!prop.writable}"> <option th:if="${!prop.required}" value="">-- 请选择 --</option> <option th:each="enumItem : ${prop.enumValues}" th:value="${enumItem.id}" th:text="${enumItem.name}"> </option> </select> </div> <button type="submit">提交表单</button> </form>
这种方式适合后端需要对表单数据做预处理的场景,比如日期格式的统一转换,或者结合业务逻辑动态调整字段属性。
方案三:适配现有JSON Schema表单库(适合前端框架项目)
如果你的项目用了React、Vue等前端框架,也可以把Activiti的JSON结构转换成标准JSON Schema,再用成熟的表单库(比如react-jsonschema-form)生成表单。需要先写一个转换函数:
function activitiToJsonSchema(formData) { const schema = { type: 'object', properties: {}, required: [] }; formData.formProperties.forEach(prop => { if (!prop.readable) return; const propSchema = {}; switch (prop.type) { case 'string': propSchema.type = 'string'; break; case 'date': propSchema.type = 'string'; propSchema.format = 'date'; break; case 'enum': propSchema.type = 'string'; propSchema.enum = prop.enumValues.map(item => item.id); propSchema.enumNames = prop.enumValues.map(item => item.name); break; } schema.properties[prop.id] = propSchema; if (prop.required) schema.required.push(prop.id); }); // 额外添加UI配置,处理读写权限 const uiSchema = {}; formData.formProperties.forEach(prop => { if (!prop.writable) { uiSchema[prop.id] = { 'ui:disabled': true }; } }); return { schema, uiSchema }; }
转换后就可以用对应的框架表单库来生成表单,这种方式适合已经在用框架表单库的项目,能复用现有组件体系。
内容的提问来源于stack exchange,提问作者Tomato
相关产品推荐
相关产品推荐

