AEM Workflow 自定义输入数据
AEM Workflow custom input data
我需要在 AEM 中创建一个工作流程,用于页面(指定为有效负载)查找页面上使用的所有资产并将它们的列表上传到外部服务。到目前为止,我已经准备好大部分代码,但业务流程要求我为每个页面使用特殊代码(工作流程的每个 运行 都不同),以便将列表上传到正确的位置。
那时我有一个问题 - 你能以某种方式为 AEM 工作流程添加更多输入值吗? 也许通过扩展开始对话框,或添加一些需要用户的特殊步骤输入?我需要能够在启动工作流时或在其 运行 时间期间以某种方式指定代码。
我已经阅读了很多文档,但由于这是我第一次使用工作流,所以我可能遗漏了一些非常明显的内容。我将不胜感激任何建议,包括对相关文档的 link。
是的,这是可能的。您需要在工作流程中实施对话步骤:https://docs.adobe.com/content/help/en/experience-manager-64/developing/extending-aem/extending-workflows/workflows-step-ref.html#dialog-participant-step
你可以:
在 AEM 中的某处创建自定义菜单条目(例如页面编辑器,/apps/wcm/core/content/editor/_jcr_content/content/items/content/header/items/headerbar/items/pageinfopopover/items/list/items/<my-action>
,请参阅库下的示例)
使用 categories="[cq.authoring.editor]"
创建客户端库。因此它作为页面编辑器的一部分加载(而不是在页面的 iframe 中)
创建一个 JS-Listener,如果单击菜单项,它会打开一个对话框(参见代码)。您可以使用普通的 Coral UI 对话框,或者我的示例滥用了 Granite 页面对话框(Granite 读取 cq:dialog 中的数据结构,并创建一个 Coral UI 组件编辑对话框它——而 Coral 是普通的 JS UI-framework)
创建一个 Java-Servlet,用于捕获您的请求并创建工作流。理论上您可以使用 AEM servlet。但是我经常不得不自己写,因为它缺少一些功能。
这是 JS 侦听器:
/*global Granite,jQuery,document,window */
(function ($, ns, channel, window) {
"use strict";
var START_WORKFLOW_ACTIVATOR_SELECTOR = ".js-editor-myexample-activator";
function onSuccess() {
ns.ui.helpers.notify({
heading: "Example Workflow",
content: "successfully started",
type: ns.ui.helpers.NOTIFICATION_TYPES.SUCCESS
});
}
function onSubmitFail(event, jqXHR) {
var errorMsg = Granite.I18n.getVar($(jqXHR.responseText).find("#Message").html());
ns.ui.helpers.notify({
heading: "Example Workflow",
content: errorMsg,
type: ns.ui.helpers.NOTIFICATION_TYPES.ERROR
});
}
function onReady() {
// add selector for special servlet to form action-url
var $form = ns.DialogFrame.currentFloatingDialog.find("form");
var action = $form.attr("action");
if (action) {
$form.attr("action", action + ".myexample-selector.html");
}
// register dialog-fail event, to show a relevant error message
$(document).on("dialog-fail", onSubmitFail);
// init your dialog here ...
}
function onClose() {
$(document).off("dialog-fail", onSubmitFail);
}
// Listen for the tap on the 'myexample' activator
channel.on("click", START_WORKFLOW_ACTIVATOR_SELECTOR, function () {
var activator = $(this);
// this is a dirty trick, to use a Granite dialog directly (point to data-structure like in cq:dialog)
var dialogUrl = Granite.HTTP.externalize("/apps/...." + Granite.author.ContentFrame.getContentPath());
var dlg = new ns.ui.Dialog({
getConfig: function () {
return {
src: dialogUrl,
loadingMode: "auto",
layout: "auto"
}
},
getRequestData: function () {
return {};
},
"onSuccess": onSuccess,
"onReady": onReady,
"onClose": onClose
});
ns.DialogFrame.openDialog(dlg);
});
}(jQuery, Granite.author, jQuery(document), window));
这是 servlet
@Component(service = Servlet.class,
property = {
SLING_SERVLET_RESOURCE_TYPES + "=cq:Page",
SLING_SERVLET_SELECTORS + "=myexample-selector",
SLING_SERVLET_METHODS + "=POST",
SLING_SERVLET_EXTENSIONS + "=html"
})
public class RequestExampleWorkflowServlet extends SlingAllMethodsServlet {
@Override
protected void doPost(@Nonnull SlingHttpServletRequest request, @Nonnull SlingHttpServletResponse response) throws IOException {
final Page page = request.getResource().adaptTo(Page.class);
if (page != null) {
Map<String, Object> wfMetaData = new HashMap<>();
wfMetaData.put("workflowTitle", "Request Translation for " + page.getTitle());
wfMetaData.put("something", "Hello World");
try {
WorkflowSession wfSession = request.getResourceResolver().adaptTo(WorkflowSession.class);
if (wfSession != null) {
WorkflowModel wfModel = wfSession.getModel("/var/workflow/models/example-workflow");
WorkflowData wfData = wfSession.newWorkflowData(PayloadInfo.PAYLOAD_TYPE.JCR_PATH.name(), page.getPath());
wfSession.startWorkflow(wfModel, wfData, wfMetaData);
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_OK, "Triggered Example Workflow");
} else {
throw new WorkflowException("Cannot retrieve WorkflowSession");
}
} catch (WorkflowException e) {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
} else {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal error - cannot get page");
}
}
}
我需要在 AEM 中创建一个工作流程,用于页面(指定为有效负载)查找页面上使用的所有资产并将它们的列表上传到外部服务。到目前为止,我已经准备好大部分代码,但业务流程要求我为每个页面使用特殊代码(工作流程的每个 运行 都不同),以便将列表上传到正确的位置。
那时我有一个问题 - 你能以某种方式为 AEM 工作流程添加更多输入值吗? 也许通过扩展开始对话框,或添加一些需要用户的特殊步骤输入?我需要能够在启动工作流时或在其 运行 时间期间以某种方式指定代码。
我已经阅读了很多文档,但由于这是我第一次使用工作流,所以我可能遗漏了一些非常明显的内容。我将不胜感激任何建议,包括对相关文档的 link。
是的,这是可能的。您需要在工作流程中实施对话步骤:https://docs.adobe.com/content/help/en/experience-manager-64/developing/extending-aem/extending-workflows/workflows-step-ref.html#dialog-participant-step
你可以:
在 AEM 中的某处创建自定义菜单条目(例如页面编辑器,
/apps/wcm/core/content/editor/_jcr_content/content/items/content/header/items/headerbar/items/pageinfopopover/items/list/items/<my-action>
,请参阅库下的示例)使用
categories="[cq.authoring.editor]"
创建客户端库。因此它作为页面编辑器的一部分加载(而不是在页面的 iframe 中)创建一个 JS-Listener,如果单击菜单项,它会打开一个对话框(参见代码)。您可以使用普通的 Coral UI 对话框,或者我的示例滥用了 Granite 页面对话框(Granite 读取 cq:dialog 中的数据结构,并创建一个 Coral UI 组件编辑对话框它——而 Coral 是普通的 JS UI-framework)
创建一个 Java-Servlet,用于捕获您的请求并创建工作流。理论上您可以使用 AEM servlet。但是我经常不得不自己写,因为它缺少一些功能。
这是 JS 侦听器:
/*global Granite,jQuery,document,window */
(function ($, ns, channel, window) {
"use strict";
var START_WORKFLOW_ACTIVATOR_SELECTOR = ".js-editor-myexample-activator";
function onSuccess() {
ns.ui.helpers.notify({
heading: "Example Workflow",
content: "successfully started",
type: ns.ui.helpers.NOTIFICATION_TYPES.SUCCESS
});
}
function onSubmitFail(event, jqXHR) {
var errorMsg = Granite.I18n.getVar($(jqXHR.responseText).find("#Message").html());
ns.ui.helpers.notify({
heading: "Example Workflow",
content: errorMsg,
type: ns.ui.helpers.NOTIFICATION_TYPES.ERROR
});
}
function onReady() {
// add selector for special servlet to form action-url
var $form = ns.DialogFrame.currentFloatingDialog.find("form");
var action = $form.attr("action");
if (action) {
$form.attr("action", action + ".myexample-selector.html");
}
// register dialog-fail event, to show a relevant error message
$(document).on("dialog-fail", onSubmitFail);
// init your dialog here ...
}
function onClose() {
$(document).off("dialog-fail", onSubmitFail);
}
// Listen for the tap on the 'myexample' activator
channel.on("click", START_WORKFLOW_ACTIVATOR_SELECTOR, function () {
var activator = $(this);
// this is a dirty trick, to use a Granite dialog directly (point to data-structure like in cq:dialog)
var dialogUrl = Granite.HTTP.externalize("/apps/...." + Granite.author.ContentFrame.getContentPath());
var dlg = new ns.ui.Dialog({
getConfig: function () {
return {
src: dialogUrl,
loadingMode: "auto",
layout: "auto"
}
},
getRequestData: function () {
return {};
},
"onSuccess": onSuccess,
"onReady": onReady,
"onClose": onClose
});
ns.DialogFrame.openDialog(dlg);
});
}(jQuery, Granite.author, jQuery(document), window));
这是 servlet
@Component(service = Servlet.class,
property = {
SLING_SERVLET_RESOURCE_TYPES + "=cq:Page",
SLING_SERVLET_SELECTORS + "=myexample-selector",
SLING_SERVLET_METHODS + "=POST",
SLING_SERVLET_EXTENSIONS + "=html"
})
public class RequestExampleWorkflowServlet extends SlingAllMethodsServlet {
@Override
protected void doPost(@Nonnull SlingHttpServletRequest request, @Nonnull SlingHttpServletResponse response) throws IOException {
final Page page = request.getResource().adaptTo(Page.class);
if (page != null) {
Map<String, Object> wfMetaData = new HashMap<>();
wfMetaData.put("workflowTitle", "Request Translation for " + page.getTitle());
wfMetaData.put("something", "Hello World");
try {
WorkflowSession wfSession = request.getResourceResolver().adaptTo(WorkflowSession.class);
if (wfSession != null) {
WorkflowModel wfModel = wfSession.getModel("/var/workflow/models/example-workflow");
WorkflowData wfData = wfSession.newWorkflowData(PayloadInfo.PAYLOAD_TYPE.JCR_PATH.name(), page.getPath());
wfSession.startWorkflow(wfModel, wfData, wfMetaData);
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_OK, "Triggered Example Workflow");
} else {
throw new WorkflowException("Cannot retrieve WorkflowSession");
}
} catch (WorkflowException e) {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
} else {
MyServletUtil.respondSlingStyleHtml(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal error - cannot get page");
}
}
}