本主题介绍如何为工作流开发自定义步骤组件,以及如何与工作流进行有序交互。
创建自定义工作流步骤涉及以下活动:
您还可以与项目和脚本中的工作流进行交互。
工作流步骤组件定义创建工作流模型时步骤的外观和行为:
与所有组件一样,工作流步骤组件继承自为sling:resourceSuperType
属性指定的组件。 下图显示了构成所有工作流步骤组件基础的cq:component
节点的层次结构。 该图还包括流程步骤、参与者步骤和动态参与者步骤组件,因为它们是开发自定义步骤组件最常见的(和基本的)起点。
您必须不要更改/libs
路径中的任何内容。
这是因为下次升级实例时,/libs
的内容会被覆盖(当您应用修补程序或功能包时,很可能会被覆盖)。
建议的配置和其他更改方法是:
/libs
的/apps
下/apps
中进行任何更改/libs/cq/workflow/components/model/step
组件是流程步骤、参与者步骤和动态参与者步骤的最接近的共同祖先,它们都继承以下项:
step.jsp
将步骤组件添加到模型时,step.jsp
脚本将呈现其标题。
包含以下选项卡的对话框:
当步骤组件的编辑对话框的选项卡与此默认外观不匹配时,该步骤组件已定义脚本、节点属性或覆盖这些继承选项卡的对话框选项卡。
ECMA脚本中提供以下对象(取决于步骤类型):
WorkItemwork Item
WorkflowSession workflowSession
WorkflowData workflowData
args
:数组。
sling
:访问其他OSGI服务。
jcrSession
您可以使用工作流元数据保留工作流生命周期中所需的信息。 工作流步骤的一个常见要求是保留数据以供将来在工作流中使用,或检索保留的数据。
有三种类型的MetaDataMap对象——用于Workflow
、WorkflowData
和WorkItem
对象。 它们都具有相同的预期用途——存储元数据。
WorkItem有自己的MetaDataMap,只能在该工作项(如步骤)运行时使用。
Workflow
和WorkflowData
元数据映射均在整个工作流中共享。 对于这些情况,建议仅使用WorkflowData
元数据映射。
工作流步骤组件可以以与任何其他组件相同的方式创建。
要继承其中一个(现有)基本步骤组件,请将以下属性添加到cq:Component
节点:
名称: sling:resourceSuperType
类型: String
值:解析到基本组件的以下路径之一:
cq/workflow/components/model/process
cq/workflow/components/model/participant
cq/workflow/components/model/dynamic_participant
请按照以下过程在Common选项卡上为Title和Description字段指定默认值。
当满足以下两个要求时,该字段值将出现在步骤实例中:
./jcr:title
./jcr:description
位置当编辑对话框使用/libs/cq/flow/components/step/step
组件实现的公用选项卡时,满足此要求。
/libs/cq/flow/components/step/step
组件实现的step.jsp
脚本。在cq:Component
节点下,添加以下节点:
cq:editConfig
cq:EditConfig
有关cq:editConfig节点的详细信息,请参阅配置组件的编辑行为。
在cq:EditConfig
节点下,添加以下节点:
cq:formParameters
nt:unstructured
将以下名称的String
属性添加到cq:formParameters
节点:
jcr:title
:该值将填充“公 用”选项卡的“标 题”字段。jcr:description
:该值将填充“公 用”选项卡的“说 明”字段。请参阅保持和访问数据。 特别是,有关在运行时访问属性值的信息,请参见在运行时访问对话框属性值。
cq:Widget
项的名称属性指定存储小部件值的JCR节点。 当工作流步骤组件对话框中的构件将值存储在./metaData
节点下时,该值将添加到工作流MetaDataMap
中。
例如,对话框中的文本字段是具有以下属性的cq:Widget
节点:
名称 | 类型 | 值 |
---|---|---|
xtype |
String |
textarea |
name |
String |
./metaData/subject |
fieldLabel |
String |
Email Subject |
在此文本字段中指定的值将添加到工作流实例的 [MetaDataMap](#metadatamaps)
对象,并与subject
键关联。
当密钥为PROCESS_ARGS
时,该值可通过args
变量在ECMA脚本实现中随时可用。 在这种情况下,name属性的值为./metaData/PROCESS_ARGS.
每个基本步骤组件使工作流模型开发人员能够在设计时配置以下主要功能:
要将组件集中在特定工作流方案中使用,请在设计中配置关键功能,并删除模型开发者对其进行更改的能力。
在cq:component节点下,添加以下节点:
cq:editConfig
cq:EditConfig
有关cq:editConfig节点的详细信息,请参阅配置组件的编辑行为。
在cq:EditConfig节点下,添加以下节点:
cq:formParameters
nt:unstructured
向cq:formParameters
节点添加String
属性。 组件super类型确定属性的名称:
PROCESS
PARTICIPANT
DYNAMIC_PARTICIPANT
指定属性的值:
PROCESS
:实现步骤行为的服务的ECMA脚本或PID的路径。PARTICIPANT
:为工作项分配的用户的ID。DYNAMIC_PARTICIPANT
:指向ECMA脚本的路径或选择用户分配工作项的服务的PID。要删除模型开发人员更改属性值的能力,请覆盖组件super类型的对话框。
自定义您的参加者步骤组件,以提供表单参加者步骤和对话框参加者步骤组件中的功能:
对新组件执行以下过程(请参阅创建自定义工作流步骤组件):
在cq:Component
节点下,添加以下节点:
cq:editConfig
cq:EditConfig
有关cq:editConfig节点的详细信息,请参阅配置组件的编辑行为。
在cq:EditConfig节点下,添加以下节点:
cq:formParameters
nt:unstructured
要在用户打开工作项时显示表单,请向cq:formParameters
节点添加以下属性:
FORM_PATH
String
要在用户完成工作项时显示自定义对话框,请向cq:formParameters
节点添加以下属性
DIALOG_PATH
String
在cq:Component
节点下,添加cq:EditConfig
节点。 在该节点下添加一个nt:unstructured
节点(必须命名为cq:formParameters
),并在该节点中添加以下属性:
名称: PROCESS_AUTO_ADVANCE
类型: Boolean
值:
true
时,工作流将运行该步骤并继续——这是默认值,也建议false
时,工作流将运行并停止;这需要额外处理,因此建议使用true
名称: DO_NOTIFY
Boolean
您可以使用工作流元数据保留工作流生命周期中以及步骤之间所需的信息。 工作流步骤的一个常见要求是保留数据以供将来使用,或从先前步骤中检索保留的数据。
工作流元数据存储在MetaDataMap
对象中。 Java API提供Workflow.getWorkflowData
方法以返回提供相应MetaDataMap
对象的WorkflowData
对象。 此WorkflowData
MetaDataMap
对象可用于步骤组件的OSGi服务或ECMA脚本。
WorkflowProcess
实现的执行方法将传递给WorkItem
对象。 使用此对象可获取当前工作流实例的WorkflowData
对象。 以下示例向工作流MetaDataMap
对象中添加一个项,然后记录每个项。 (“mykey”、“My Step Value”)项可用于工作流中的后续步骤。
public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException {
MetaDataMap wfd = item.getWorkflow().getWorkflowData().getMetaDataMap();
wfd.put("mykey", "My Step Value");
Set<String> keyset = wfd.keySet();
Iterator<String> i = keyset.iterator();
while (i.hasNext()){
Object key = i.next();
log.info("The workflow medata includes key {} and value {}",key.toString(),wfd.get(key).toString());
}
}
graniteWorkItem
变量是当前WorkItem
Java对象的ECMA脚本表示形式。 因此,您可以使用graniteWorkItem
变量获取工作流元数据。 以下ECMA脚本可用于实现处理步骤,以向工作流MetaDataMap
对象添加一个项,然后记录每个项。 这些项目随后便可用于工作流中的后续步骤。
步骤脚本直接可用的metaData
变量是步骤的元数据。 步骤元数据与工作流元数据不同。
var currentDateInMillis = new Date().getTime();
graniteWorkItem.getWorkflowData().getMetaDataMap().put("hardcodedKey","theKey");
graniteWorkItem.getWorkflowData().getMetaDataMap().put("currentDateInMillisKey",currentDateInMillis);
var iterator = graniteWorkItem.getWorkflowData().getMetaDataMap().keySet().iterator();
while (iterator.hasNext()){
var key = iterator.next();
log.info("Workflow metadata key, value = " + key.toString() + ", " + graniteWorkItem.getWorkflowData().getMetaDataMap().get(key));
}
工作流实例的MetaDataMap
对象可用于在工作流的整个生命周期中存储和检索数据。 对于工作流步骤组件实现,MetaDataMap
对于在运行时检索组件属性值尤为有用。
有关配置组件对话框以将属性存储为工作流元数据的信息,请参阅在工作流元数据中保存属性值。
工作流MetaDataMap
可用于Java和ECMA脚本进程实现:
在WorkflowProcess接口的Java实现中,args
参数是工作流的MetaDataMap
对象。
在ECMA脚本实现中,该值可使用args
和metadata
变量。
进程步骤组件的编辑对话框包括参数属性。 Arguments属性的值存储在工作流元数据中,并与PROCESS_ARGS
键相关联。
在下图中,Arguments属性的值为argument1, argument2
:
以下Java代码是WorkflowProcess
实现的execute
方法。 该方法将值记录在与PROCESS_ARGS
键关联的args
MetaDataMap
中。
public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException {
if (args.containsKey("PROCESS_ARGS")){
log.info("workflow metadata for key PROCESS_ARGS and value {}",args.get("PROCESS_ARGS","string").toString());
}
}
当执行使用此Java实现的进程步骤时,日志包含以下条目:
16.02.2018 12:07:39.566 *INFO* [JobHandler: /var/workflow/instances/server0/2018-02-16/model_855140139900189:/content/we-retail/de] com.adobe.example.workflow.impl.process.LogArguments workflow metadata for key PROCESS_ARGS and value argument1, argument2
以下ECMA脚本用作进程步骤的进程。 它记录参数数和参数值:
var iterator = graniteWorkItem.getWorkflowData().getMetaDataMap().keySet().iterator();
while (iterator.hasNext()){
var key = iterator.next();
log.info("Workflow metadata key, value = " + key.toString() + ", " + graniteWorkItem.getWorkflowData().getMetaDataMap().get(key));
}
log.info("hardcodedKey "+ graniteWorkItem.getWorkflowData().getMetaDataMap().get("hardcodedKey"));
log.info("currentDateInMillisKey "+ graniteWorkItem.getWorkflowData().getMetaDataMap().get("currentDateInMillisKey"));
本节介绍如何使用流程步骤的参数。 该信息也适用于动态参加者选择器。
有关在工作流元数据中存储组件属性的另一个示例,请参阅示例:创建记录器工作流步骤。 此示例提供一个对话框,它将元数据值与PROCESS_ARGS以外的键相关联。
在进程步骤组件的脚本中,参数可通过args
对象使用。
创建自定义步骤组件时,对象metaData
在脚本中可用。 此对象仅限于单个字符串参数。
当在工作流的过程中启动进程步骤时,这些步骤会向OSGi服务发送请求或执行ECMA脚本。 开发执行工作流所需操作的服务或ECMA脚本。
要将进程步骤定义为OSGI服务组件(Java捆绑):
创建捆绑包并将其部署到OSGI容器。 请参阅有关创建具有CRXDE Lite或Eclipse的捆绑的文档。
OSGI组件需要使用其execute()
方法实现WorkflowProcess
接口。 请参阅下面的示例代码。
需要将包名称添加到maven-bundle-plugin
配置的<*Private-Package*>
部分。
添加SCR属性process.label
并根据需要设置值。 这将是使用通用进程步骤组件时列出的进程步骤的名称。 请参阅以下示例。
在模型编辑器中,使用通用流程步骤组件将流程步骤添加到工作流。
在编辑对话框(位于进程步骤中)中,转到进程选项卡,然后选择您的进程实现。
如果在代码中使用参数,请设置进程参数。 例如:错误。
保存步骤和工作流模型(模型编辑器的左上角)的更改。
Java方法(分别实现可执行Java方法的类)注册为OSGI服务,使您能够在运行时随时添加方法。
当有效负荷是页面时,以下OSGI组件将属性approved
添加到页面内容节点:
package com.adobe.example.workflow.impl.process;
import com.adobe.granite.workflow.WorkflowException;
import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.WorkItem;
import com.adobe.granite.workflow.exec.WorkflowData;
import com.adobe.granite.workflow.exec.WorkflowProcess;
import com.adobe.granite.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
/**
* Sample workflow process that sets an <code>approve</code> property to the payload based on the process argument value.
*/
@Component
@Service
public class MyProcess implements WorkflowProcess {
@Property(value = "An example workflow process implementation.")
static final String DESCRIPTION = Constants.SERVICE_DESCRIPTION;
@Property(value = "Adobe")
static final String VENDOR = Constants.SERVICE_VENDOR;
@Property(value = "My Sample Workflow Process")
static final String LABEL="process.label";
private static final String TYPE_JCR_PATH = "JCR_PATH";
public void execute(WorkItem item, WorkflowSession session, MetaDataMap args) throws WorkflowException {
WorkflowData workflowData = item.getWorkflowData();
if (workflowData.getPayloadType().equals(TYPE_JCR_PATH)) {
String path = workflowData.getPayload().toString() + "/jcr:content";
try {
Session jcrSession = session.adaptTo(Session.class);
Node node = (Node) jcrSession.getItem(path);
if (node != null) {
node.setProperty("approved", readArgument(args));
jcrSession.save();
}
} catch (RepositoryException e) {
throw new WorkflowException(e.getMessage(), e);
}
}
}
private boolean readArgument(MetaDataMap args) {
String argument = args.get("PROCESS_ARGS", "false");
return argument.equalsIgnoreCase("true");
}
}
如果流程在一行中失败三次,则会将项目放在工作流管理员的收件箱中。
ECMA脚本使脚本开发人员能够实施进程步骤。 脚本位于JCR存储库中,并从中执行。
下表列表了可立即用于处理脚本的变量,从而提供对工作流Java API对象的访问。
Java类 | 脚本变量名称 | 描述 |
---|---|---|
com.adobe.granite.workflow.exec.WorkItem |
graniteWorkItem |
当前步骤实例。 |
com.adobe.granite.workflow.WorkflowSession |
graniteWorkflowSession |
当前步骤实例的工作流会话。 |
String[] (包含进程参数) |
args |
步骤参数。 |
com.adobe.granite.workflow.metadata.MetaDataMap |
metaData |
当前步骤实例的元数据。 |
org.apache.sling.scripting.core.impl.InternalScriptHelper |
sling |
提供对Sling运行时环境的访问。 |
以下示例脚本演示如何访问表示工作流有效负荷的JCR节点。 graniteWorkflowSession
变量适用于JCR会话变量,该会话变量用于从有效负荷路径获得节点。
var workflowData = graniteWorkItem.getWorkflowData();
if (workflowData.getPayloadType() == "JCR_PATH") {
var path = workflowData.getPayload().toString();
var jcrsession = graniteWorkflowSession.adaptTo(Packages.javax.jcr.Session);
var node = jcrsession.getNode(path);
if (node.hasProperty("approved")){
node.setProperty("approved", args[0] == "true" ? true : false);
node.save();
}
}
以下脚本检查有效负荷是否为图像(.png
文件),从它创建黑白图像,并将其另存为同级节点。
var workflowData = graniteWorkItem.getWorkflowData();
if (workflowData.getPayloadType() == "JCR_PATH") {
var path = workflowData.getPayload().toString();
var jcrsession = graniteWorkflowSession.adaptTo(Packages.javax.jcr.Session);
var node = jcrsession.getRootNode().getNode(path.substring(1));
if (node.isNodeType("nt:file") && node.getProperty("jcr:content/jcr:mimeType").getString().indexOf("image/") == 0) {
var is = node.getProperty("jcr:content/jcr:data").getStream();
var layer = new Packages.com.day.image.Layer(is);
layer.grayscale();
var parent = node.getParent();
var gn = parent.addNode("grey" + node.getName(), "nt:file");
var content = gn.addNode("jcr:content", "nt:resource");
content.setProperty("jcr:mimeType","image/png");
var cal = Packages.java.util.Calendar.getInstance();
content.setProperty("jcr:lastModified",cal);
var f = Packages.java.io.File.createTempFile("test",".png");
var tout = new Packages.java.io.FileOutputStream(f);
layer.write("image/png", 1.0, tout);
var fis = new Packages.java.io.FileInputStream(f);
content.setProperty("jcr:data", fis);
parent.save();
tout.close();
fis.close();
is.close();
f.deleteOnExit();
}
}
要使用脚本:
创建脚本(例如,CRXDE Lite)并将其保存在/apps/myapp/workflow/scripts
下的存储库中
要指定在进程步骤编辑对话框中标识脚本的标题,请将以下属性添加到脚本的jcr:content
节点:
名称 | 类型 | 值 |
---|---|---|
jcr:mixinTypes |
Name[] |
mix:title |
jcr:title |
String |
要在编辑对话框中显示的名称。 |
编辑进程步骤实例并指定要使用的脚本。
您可以为动态参与者步骤组件开发参与者选择器。
当在工作流期间启动动态参与者步骤组件时,该步骤需要确定可以将生成的工作项分配到的参与者。 要执行此操作,请执行以下任一步骤:
您可以开发服务或ECMA脚本,该脚本根据工作流的要求选择参加者。
要将参与者步骤定义为OSGI服务组件(Java类):
OSGI组件需要使用其getParticipant()
方法实现ParticipantStepChooser
接口。 请参阅下面的示例代码。
创建捆绑包并将其部署到OSGI容器。
添加SCR属性chooser.label
并根据需要设置值。 这将是使用动态参与者步骤组件列出参加者选择者的名称。 请参阅示例:
package com.adobe.example.workflow.impl.process;
import com.adobe.granite.workflow.WorkflowException;
import com.adobe.granite.workflow.WorkflowSession;
import com.adobe.granite.workflow.exec.ParticipantStepChooser;
import com.adobe.granite.workflow.exec.WorkItem;
import com.adobe.granite.workflow.exec.WorkflowData;
import com.adobe.granite.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
/**
* Sample dynamic participant step that determines the participant based on a path given as argument.
*/
@Component
@Service
public class MyDynamicParticipant implements ParticipantStepChooser {
@Property(value = "An example implementation of a dynamic participant chooser.")
static final String DESCRIPTION = Constants.SERVICE_DESCRIPTION;
@Property(value = "Adobe")
static final String VENDOR = Constants.SERVICE_VENDOR;
@Property(value = "Dynamic Participant Chooser Process")
static final String LABEL=ParticipantStepChooser.SERVICE_PROPERTY_LABEL;
private static final String TYPE_JCR_PATH = "JCR_PATH";
public String getParticipant(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
WorkflowData workflowData = workItem.getWorkflowData();
if (workflowData.getPayloadType().equals(TYPE_JCR_PATH)) {
String path = workflowData.getPayload().toString();
String pathFromArgument = args.get("PROCESS_ARGS", String.class);
if (pathFromArgument != null && path.startsWith(pathFromArgument)) {
return "admin";
}
}
return "administrators";
}
}
在模型编辑器中,使用通用动态参与者步骤组件将动态参与者步骤添加到工作流。
在编辑对话框中,选择参加者选择器选项卡,然后选择选择器实现。
如果在代码中使用参数,请设置进程参数。 对于此示例:/content/we-retail/de
。
保存步骤和工作流模型的更改。
您可以创建一个ECMA脚本,该脚本选择分配了参与者步骤生成的工作项的用户。 脚本必须包含一个名为getParticipant
的函数,该函数不需要参数,并返回一个String
,该<a1/>包含用户或组的ID。
脚本位于JCR存储库中,并从中执行。
下表列表了变量,这些变量提供对脚本中工作流Java对象的即时访问。
Java类 | 脚本变量名称 |
---|---|
com.adobe.granite.workflow.exec.WorkItem |
graniteWorkItem |
com.adobe.granite.workflow.WorkflowSession |
graniteWorkflowSession |
String[] (包含进程参数) |
args |
com.adobe.granite.workflow.metadata.MetaDataMap |
metaData |
org.apache.sling.scripting.core.impl.InternalScriptHelper |
sling |
function getParticipant() {
var workflowData = graniteWorkItem.getWorkflowData();
if (workflowData.getPayloadType() == "JCR_PATH") {
var path = workflowData.getPayload().toString();
if (path.indexOf("/content/we-retail/de") == 0) {
return "admin";
} else {
return "administrators";
}
}
}
创建脚本(例如,CRXDE Lite)并将其保存在/apps/myapp/workflow/scripts
下的存储库中
要指定在进程步骤编辑对话框中标识脚本的标题,请将以下属性添加到脚本的jcr:content
节点:
名称 | 类型 | 值 |
---|---|---|
jcr:mixinTypes |
Name[] |
mix:title |
jcr:title |
String |
要在编辑对话框中显示的名称。 |
编辑动态参与者步骤实例并指定要使用的脚本。
工作 流包可以传递到工作流进行处理。工作流包包含对资源(如页面和资产)的引用。
您可以开发工作流步骤,以获取包资源并对其进行处理。 com.day.cq.workflow.collection
包的以下成员提供对工作流包的访问:
ResourceCollection
:工作流包类。ResourceCollectionUtil
:用于检索ResourceCollection对象。ResourceCollectionManager
:创建和检索集合。将实现部署为OSGi服务。以下示例Java类演示如何获取包资源:
package com.adobe.example;
import java.util.ArrayList;
import java.util.List;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.collection.ResourceCollection;
import com.day.cq.workflow.collection.ResourceCollectionManager;
import com.day.cq.workflow.collection.ResourceCollectionUtil;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Reference;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@Component
@Service
public class LaunchBulkActivate implements WorkflowProcess {
private static final Logger log = LoggerFactory.getLogger(LaunchBulkActivate.class);
@Property(value="Bulk Activate for Launches")
static final String PROCESS_NAME ="process.label";
@Property(value="A sample workflow process step to support Launches bulk activation of pages")
static final String SERVICE_DESCRIPTION = Constants.SERVICE_DESCRIPTION;
@Reference
private ResourceCollectionManager rcManager;
public void execute(WorkItem workItem, WorkflowSession workflowSession) throws Exception {
Session session = workflowSession.getSession();
WorkflowData data = workItem.getWorkflowData();
String path = null;
String type = data.getPayloadType();
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String payloadData = (String) data.getPayload();
if (session.itemExists(payloadData)) {
path = payloadData;
}
} else if (data.getPayload() != null && type.equals(TYPE_JCR_UUID)) {
Node node = session.getNodeByUUID((String) data.getPayload());
path = node.getPath();
}
// CUSTOMIZED CODE IF REQUIRED....
if (path != null) {
// check for resource collection
ResourceCollection rcCollection = ResourceCollectionUtil.getResourceCollection((Node)session.getItem(path), rcManager);
// get list of paths to replicate (no resource collection: size == 1
// otherwise size >= 1
List<String> paths = getPaths(path, rcCollection);
for (String aPath: paths) {
// CUSTOMIZED CODE....
}
} else {
log.warn("Cannot process because path is null for this " + "workitem: " + workItem.toString());
}
}
/**
* helper
*/
private List<String> getPaths(String path, ResourceCollection rcCollection) {
List<String> paths = new ArrayList<String>();
if (rcCollection == null) {
paths.add(path);
} else {
log.debug("ResourceCollection detected " + rcCollection.getPath());
// this is a resource collection. the collection itself is not
// replicated. only its members
try {
List<Node> members = rcCollection.list(new String[]{"cq:Page", "dam:Asset"});
for (Node member: members) {
String mPath = member.getPath();
paths.add(mPath);
}
} catch(RepositoryException re) {
log.error("Cannot build path list out of the resource collection " + rcCollection.getPath());
}
}
return paths;
}
}
开始创建自定义步骤的一种简单方法是从以下位置复制现有步骤:
/libs/cq/workflow/components/model
在/apps下重新创建路径;例如:
/apps/cq/workflow/components/model
新文件夹的类型为nt:folder
:
- apps
- cq
- workflow (nt:folder)
- components (nt:folder)
- model (nt:folder)
此步骤不适用于经典UI模型编辑器。
然后,将复制的步骤放在/apps文件夹中;例如:
/apps/cq/workflow/components/model/myCustomStep
下面是我们的示例自定义步骤的结果:
由于在标准UI中,卡上不显示仅标题而非详细信息,因此与经典UI编辑器一样,不需要details.jsp
。
将以下属性应用于节点:
/apps/cq/workflow/components/model/myCustomStep
权益物业:
sling:resourceSuperType
必须继承现有步骤。
在此示例中,我们继承了位于cq/workflow/components/model/step
的基本步骤,但您可以使用其他超类型,如participant
、process
等。
jcr:title
是在步骤浏览器(工作流模型编辑器的左侧面板)中列出组件时显示的标题。
cq:icon
用于为步骤指定Coral图标。
componentGroup
必须是以下项之一:
您现在可以打开一个工作流模型进行编辑。 在步骤浏览器中,您可以进行筛选,以查看我的自定义步骤:
将我的自定义步骤拖到模型上会显示卡:
如果尚未为该步骤定义cq:icon
,则使用标题的前两个字母显示默认图标。 例如:
在创建基本步骤后,按如下方式定义步骤配置对话框:
按如下方式在节点cq:editConfig
上配置属性:
权益物业:
cq:inherit
如果设置为true
,则您的步骤组件将继承您在sling:resourceSuperType
中指定的步骤的属性。
cq:disableTargeting
根据需要设置。
按如下方式在节点cq:formsParameter
上配置属性:
权益物业:
jcr:title
在模型映射中和我的自定义——步骤属性配置对话框的标题字段中设置步骤卡的默认标题。
您还可以定义自己的自定义属性。
在节点cq:listeners
上配置属性。
cq:listener
节点及其属性允许您在触屏优化UI模型编辑器中设置对事件做出响应的事件处理函数;例如,将步骤拖动到模型页面或编辑步骤属性。
利息物业:
afterMove: REFRESH_PAGE
afterdelete: CQ.workflow.flow.Step.afterDelete
afteredit: CQ.workflow.flow.Step.afterEdit
afterinsert: CQ.workflow.flow.Step.afterInsert
此配置对于编辑器的正常工作至关重要。 在大多数情况下,此配置不得更改。
但是,将cq:inherit
设置为true(在cq:editConfig
节点上,请参见上文)可以继承此配置,无需在步骤定义中显式地包含它。 如果没有继承,则您需要添加此节点并包含以下属性和值。
在此示例中,已激活继承,因此我们可以删除cq:listeners
节点,并且该步骤仍可正常工作。
您现在可以将步骤的实例添加到工作流模型。 当您配置时,您将看到以下对话框:
自定义步骤的标记在组件根节点的.content.xml
中表示。 此示例使用的示例.content.xml
:
/apps/cq/workflow/components/model/myCustomStep/.content.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="https://sling.apache.org/jcr/sling/1.0" xmlns:cq="https://www.day.com/jcr/cq/1.0" xmlns:jcr="https://www.jcp.org/jcr/1.0"
cq:icon="bell"
jcr:primaryType="cq:Component"
jcr:title="My Custom Step"
sling:resourceSuperType="cq/workflow/components/model/process"
allowedParents="[*/parsys]"
componentGroup="Workflow"/>
此示例中使用的_cq_editConfig.xml
示例:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="https://www.day.com/jcr/cq/1.0" xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:nt="https://www.jcp.org/jcr/nt/1.0"
cq:disableTargeting="{Boolean}true"
cq:inherit="{Boolean}true"
jcr:primaryType="cq:EditConfig">
<cq:formParameters
jcr:primaryType="nt:unstructured"
jcr:title="My Custom Step Card"
SAMPLE_PROPERY="sample value"/>
<cq:listeners
jcr:primaryType="cq:EditListenersConfig"
afterdelete="CQ.workflow.flow.Step.afterDelete"
afteredit="CQ.workflow.flow.Step.afterEdit"
afterinsert="CQ.workflow.flow.Step.afterInsert"
afterMove="REFRESH_PAGE"/>
</jcr:root>
此示例中使用的_cq_dialog/.content.xml
示例:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="https://sling.apache.org/jcr/sling/1.0" xmlns:cq="https://www.day.com/jcr/cq/1.0" xmlns:jcr="https://www.jcp.org/jcr/1.0" xmlns:nt="https://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="My Custom - Step Properties"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<common
cq:hideOnEdit="true"
jcr:primaryType="nt:unstructured"
jcr:title="Common"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"/>
<process
cq:hideOnEdit="true"
jcr:primaryType="nt:unstructured"
jcr:title="Process"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"/>
<mycommon
jcr:primaryType="nt:unstructured"
jcr:title="Common"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
<items jcr:primaryType="nt:unstructured">
<columns
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<title
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Title"
name="./jcr:title"/>
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./jcr:description"/>
</items>
</columns>
</items>
</mycommon>
<advanced
jcr:primaryType="nt:unstructured"
jcr:title="Advanced"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns">
<items jcr:primaryType="nt:unstructured">
<columns
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<email
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
fieldDescription="Notify user via email."
fieldLabel="Email"
name="./metaData/PROCESS_AUTO_ADVANCE"
text="Notify user via email."
value="true"/>
</items>
</columns>
</items>
</advanced>
</items>
</content>
</jcr:root>
注意对话框定义中的公用节点和进程节点。 这些属性继承自我们用作自定义步骤超类型的流程步骤:
sling:resourceSuperType : cq/workflow/components/model/process
经典UI模型编辑器对话框仍可用于标准的触屏优化UI编辑器。
如果要将经典UI步骤对话框升级到标准UI对话框,尽管AEM有对话框转换工具。 转换后,某些情况下仍可对对话框进行手动改进。
如果升级的对话框为空,您可以查看/libs
中的功能与如何提供解决方案的示例类似的对话框。 例如:
/libs/cq/workflow/components/model
/libs/cq/workflow/components/workflow
/libs/dam/components
/libs/wcm/workflow/components/autoassign
/libs/cq/projects
您不得修改/libs
中的任何内容,只需将它们作为示例使用即可。 如果要利用任何现有步骤,请将它们复制到/apps
,然后在此进行修改。