Activiti - Geschäftsprozess-Engine

Activiti Framework (Java) - Beschreibung des XML-Taskflows (bpm) und seiner Verwaltung. Hier beschreibe ich die grundlegenden Konzepte und den Aufbau einfacher Geschäftsprozesse.

Das Hauptkonzept von Activiti ist ein Prozess und eine Aufgabe. Ein Prozess sind alle Aufgaben, die durch gerichtete Abläufe und Zweige miteinander verbunden sind.

Ich werde auf solche Aspekte eingehen:

  • - Activiti in seiner reinsten Form
  • - Benutzer, Rollen
  • - SpringBoot anschließen
  • - REST-API
  • - Job und Delegierter

Die Bewegung der Flüsse erfolgt schrittweise von Aufgabe zu Aufgabe. Jeder dieser Schritte unterbricht den Prozess, während auf die Eingabe und den Abschluss der Aufgabe gewartet wird. Alle Zwischenaktionen werden in der Datenbank gespeichert.

Wo, was ich nehmen soll, werde ich unten angeben. Beginnen wir mit einem einfachen Beispiel - dem Programmentwicklungsprozess, der aus dem Schreiben von Code und dem Testen besteht. Unten ist ein Prozessdiagramm.

Bild

Dies ist alles ein Prozess, es hat eine ID, einen Namen und andere Eigenschaften.

Bild

Es hat:

Der Beginn des Prozesses, zwei Aufgaben "Entwickeln" und "Testen", ein Zweig (Gateway) und das Ende des Prozesses. In Worten, alles passiert so:

  • Laden der BPM-Beschreibung
  • Starten Sie den Prozess
  • Nach dem Start fallen wir sofort in die Entwicklungsaufgabe
  • Nach der Ausführung von Develop wird es getestet und gemäß dem Testergebnis endet der Prozess oder kehrt wieder zur Entwicklung zurück.

Activiti besteht aus einer Reihe von Diensten

Hier sind die wichtigsten:

  • RepositoryService: Steuert das Laden von Prozessbeschreibungen
  • RuntimeService: Startet Prozesse
  • TaskService: Führt Aufgaben aus
  • FormService: Zugriff auf Taskvariablen
  • HistoryService: Zugriff auf den Prozessverlauf
  • IdentityService: Benutzer und Rollen

Activiti in seiner reinsten Form


Aber alles beginnt mit der Konfiguration und Datei - activiti.cfg.xml.

Daraus

ProcessEngineConfiguration cfg = ProcessEngineConfiguration .createProcessEngineConfigurationFromResource("activiti.cfg.xml"); 

Wenn Sie Ihre Konfiguration nicht verwenden, stellt Activiti die Datenbank im H2-Speicher selbst bereit. Dies passt nicht zu mir, aber mein geliebtes Oracle ist voll. Es gibt Optionen zum Verbinden verschiedener Datenbanken.

Hier ist meine Konfiguration

activiti.cfg.xml
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe" /> <property name="jdbcDriver" value="oracle.jdbc.driver.OracleDriver" /> <property name="jdbcUsername" value="BPM" /> <property name="jdbcPassword" value="1" /> <!-- Database configurations --> <property name="databaseSchemaUpdate" value="false" /> <property name="asyncExecutorActivate" value="false" /> <!-- mail server configurations --> <property name="mailServerPort" value="5025" /> </bean> </beans> 


Wir ändern die Werte in "property name = jdbc *" und verbinden eine andere Datenbank

Projektstruktur



POM
 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>DemoActiviti</groupId> <artifactId>DemoActiviti</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.activiti</groupId> <version>6.0.0</version> <artifactId>activiti-spring-boot-starter-integration</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0</version> </dependency> </dependencies> <build> <plugins> <!-- Maven Assembly Plugin --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.4.1</version> <configuration> <!-- get all project dependencies --> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <!-- MainClass in mainfest make a executable jar --> <archive> <manifest> <mainClass>com.example.DemoActiviti</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <!-- bind to the packaging phase --> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> 


Das Vorhandensein des Plugins "Maven-Assembly-Plugin" im POM ermöglicht es Ihnen, ein JAR zu erstellen (zu verpacken), das mit Abhängigkeiten gestartet und ausgeführt wird -
 java -jar DemoActiviti-1.0-SNAPSHOT-jar-with-dependencies.jar 

JDBC-Treiber für Oracle im lokalen Maven-Repository installiert

 mvn install:install-file -Dfile={Path/to/your/ojdbc6.jar} -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0 -Dpackaging=jar 

log4j
 log4j.rootLogger=WARN, ACT log4j.appender.ACT=org.apache.log4j.ConsoleAppender log4j.appender.ACT.layout=org.apache.log4j.PatternLayout log4j.appender.ACT.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n 


Für diesen Prozess definieren wir 4 Aktionen: BPM-Laden, Prozessstart, Entwicklung und Testen. Jede Aktion hat einen entsprechenden Parameter: Bereitstellen, Starten, Entwickeln, Testen.

Wir nehmen Skripte für eine Datenbank von
Activiti-Get-Started
dort im Ordner \ activiti-6.0.0 \ activiti-6.0.0 \ database \ create - Skripte zum Erstellen einer Datenbank

Benutzer, Rollen


Bereiten Sie Benutzer und Rollen vor:

Identität
 public class DemoActiviti { private static final String DEV_PROCESS = "devProcess"; public static void main(String[] args) { Locale.setDefault(Locale.ENGLISH); ProcessEngineConfiguration cfg = ProcessEngineConfiguration .createProcessEngineConfigurationFromResource("activiti.cfg.xml"); ProcessEngine processEngine = cfg.buildProcessEngine(); createIdentity(processEngine, "programmer", "programmers"); createIdentity(processEngine, "tester", "testers"); } public static void createIdentity(ProcessEngine processEngine, String userName, String userGroup) { IdentityService identityService = processEngine.getIdentityService(); String userId = userName + "Id"; if (identityService.createUserQuery().userId(userId).count() == 0) { User user = identityService.newUser(userName); user.setId(userId); user.setEmail(userName + "@gmail.com"); identityService.saveUser(user); System.out.println("user created success fully"); } String groupId = userGroup + "Id"; if (identityService.createGroupQuery().groupId(groupId).count() == 0) { Group group = identityService.newGroup(userGroup); group.setName(userGroup); group.setId(groupId); identityService.saveGroup(group); System.out.println("group created success fully"); } if (identityService.createGroupQuery().groupId(groupId).list().size() > 0) { identityService.createMembership(userId, groupId); System.out.println("user to group success fully"); } } } 


Erstellen Sie Benutzer und Gruppen, Entwickler bzw. Tester.

In der Datenbank werden alle Tabellen durch die entsprechenden Dienste unterteilt und haben Präfixe

ACT_RE_ *: Repository.
ACT_RU_ *: Laufzeit.
ACT_ID_ *: Identität.
ACT_HI _ *: Geschichte
und so weiter

Nach dem Erstellen von Benutzern aus können Sie hier sehen

Bild

Wir werden unsere Aufgaben in der Beschreibung den entsprechenden Gruppen (CandidateGroup) zuordnen, zum Beispiel die Aufgabe Entwickeln den Gruppenprogrammierern

Bild

Als erstes platzieren wir das Programm in der Datenbank "MyProcess.bpmn" und führen das Programm mit dem Befehl deploy aus

 java -jar DemoActiviti-1.0-SNAPSHOT-jar-with-dependencies.jar deploy 

Starten Sie als Nächstes den Startvorgang

 java -jar DemoActiviti-1.0-SNAPSHOT-jar-with-dependencies.jar start 

Nach dem Delpoy- und Startvorgang werden die entsprechenden Einträge in der Datenbank angezeigt.

Repository

Bild

Laufzeit, welche Aufgabe ausgeführt wird

Bild

wem ist zugeordnet

Bild

Im Code sieht es so aus (der vollständige Code wird unten sein):

bereitstellen

 deployment = repositoryService.createDeployment() .addClasspathResource("processes/MyProcess.bpmn").deploy() 

starten

 ProcessInstance myProcess = runtimeService.startProcessInstanceByKey(DEV_PROCESS); 

entwickeln

Danach können Sie mit der Fertigstellung der Entwicklungsaufgabe beginnen.

 java -jar DemoActiviti-1.0-SNAPSHOT-jar-with-dependencies.jar develop 

  //    tasks = taskService.createTaskQuery().taskCandidateGroup("programmers").list(); 

In der Entwicklungsaufgabe wird eine "Issue" -Variable definiert

Bild

Nach der Verarbeitung der Variablen mit FormService wird die Task ausgeführt

 for (Task task : tasks) { System.out.println("Task:" + task.getTaskDefinitionKey() + ", id=" + task.getId()); FormData formData = formService.getTaskFormData(task.getId()); Map<String, Object> variables = new HashMap<String, Object>(); //   for (FormProperty formProperty : formData.getFormProperties()) { System.out.println("Enter varName <" + formProperty.getName() +">:"); String value = scanner.nextLine(); variables.put(formProperty.getId(), value); } //   taskService.complete(task.getId(), variables); System.out.println("Task complete success:" + task.getTaskDefinitionKey()); } 

Bild

Für die Entwicklungsaufgabe werden Sie aufgefordert, eine Variable einzugeben.

In der Verlaufstabelle sehen Sie die Variablen und Werte der Aufgabe, des Prozesses

Bild

Wenn der Prozess nach dem Beenden der Entwicklungsaufgabe beendet wird, wird der Status in der Datenbank gespeichert.

Im Allgemeinen sieht die Schleife folgendermaßen aus:

Fordern Sie eine Aufgabe für einen Executor an

 tasks = taskService.createTaskQuery().taskCandidateGroup("...").list(); 

Definition von Variablen

 Map<String, Object> variables = new HashMap<String, Object>(); ... variables.put("var_1", value); 

Aufgabenausführung

 taskService.complete(task.getId(), variables); 

Überprüfen Sie das Ende des Prozesses

 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(processInstance.getId()).singleResult(); if (processInstance != null && !processInstance.isEnded()) 

Nach jeder Aufgabenausführung wird der Prozess angehalten, bis eine neue Aufgabe abgeschlossen ist.
Nachdem wir Develop ausgeführt haben, fahren wir mit der Testaufgabe fort. Hier werden wir auch aufgefordert, die Variable "devResult" einzugeben - das Entwicklungsergebnis (es hat nicht richtig funktioniert, noch bevor der Test beginnt, geben Sie das Ergebnis ein), und dann wird das Ergebnis verzweigt oder endet (Ok) oder Entwicklung erneut (Nein), siehe Prozessdiagramm.

Bild

In diesem Fall ist die Entwicklung usw. Wenn Sie jetzt Aufgaben für den Entwickler anfordern, werden diese ausgeführt, aber zum Testen - nein.

Programmcode
 package com.example; import org.activiti.engine.*; import org.activiti.engine.form.FormData; import org.activiti.engine.form.FormProperty; import org.activiti.engine.repository.Deployment; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.apache.commons.lang3.StringUtils; import java.util.*; public class DemoActiviti { private static final String DEV_PROCESS = "devProcess"; public static void main(String[] args) { Locale.setDefault(Locale.ENGLISH); ProcessEngineConfiguration cfg = ProcessEngineConfiguration .createProcessEngineConfigurationFromResource("activiti.cfg.xml"); ProcessEngine processEngine = cfg.buildProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); String mode = StringUtils.EMPTY; if (args.length > 0) { mode = args[0]; } System.out.println("Processes mode: " + mode); Deployment deployment; if ("deploy".equals(mode)) { deployment = repositoryService.createDeployment() .addClasspathResource("processes/MyProcess.bpmn").deploy(); System.out.println("deploy process success"); System.exit(0); } else { List<Deployment> myProcesses = repositoryService.createDeploymentQuery() .processDefinitionKey(DEV_PROCESS).list(); deployment = myProcesses.get(myProcesses.size()-1); System.out.println("get process success:" + deployment.getId()); } // RuntimeService runtimeService = processEngine.getRuntimeService(); ProcessInstance processInstance; if ("start".equals(mode)){ ProcessInstance myProcess = runtimeService.startProcessInstanceByKey(DEV_PROCESS); System.out.println("start process success:" + myProcess.getName() +", id="+ myProcess.getId()); System.exit(0); } processInstance = runtimeService.createProcessInstanceQuery().deploymentId(deployment.getId()).singleResult(); TaskService taskService = processEngine.getTaskService(); FormService formService = processEngine.getFormService(); List<Task> tasks = new ArrayList<>(); if ("develop".equals(mode)) { System.out.println("develop mode"); //     tasks = taskService.createTaskQuery().taskCandidateGroup("programmers").list(); if (tasks.isEmpty()) { System.out.println("   "); System.exit(0); } } if ("test".equals(mode)) { System.out.println("test mode"); //     tasks = taskService.createTaskQuery().taskCandidateGroup("testers").list(); if (tasks.isEmpty()) { System.out.println("   "); System.exit(0); } } Scanner scanner = new Scanner(System.in); if (processInstance != null && !processInstance.isEnded()) { System.out.println("tasks count: [" + tasks.size() + "]"); for (Task task : tasks) { System.out.println("Task:" + task.getTaskDefinitionKey() + ", id=" + task.getId()); FormData formData = formService.getTaskFormData(task.getId()); Map<String, Object> variables = new HashMap<String, Object>(); //   for (FormProperty formProperty : formData.getFormProperties()) { System.out.println("Enter varName <" + formProperty.getName() +">:"); String value = scanner.nextLine(); variables.put(formProperty.getId(), value); } //   taskService.complete(task.getId(), variables); System.out.println("Task complete success:" + task.getTaskDefinitionKey()); } // Re-query the process instance, making sure the latest state is available //processInstance = runtimeService.createProcessInstanceQuery() // .processInstanceId(processInstance.getId()).singleResult(); } } } 


Verbinden Sie SpringBoot


Wir modifizieren das Projekt mit Spring

Fügen Sie Abhängigkeiten zu POM hinzu

POM mit SpringBoot
  <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-basic</artifactId> <version>6.0.0</version> </dependency> <dependency> <groupId>org.activiti</groupId> <version>6.0.0</version> <artifactId>activiti-spring-boot-starter-integration</artifactId> </dependency> .... 


Die DemoActiviti-Klasse ist jetzt so geworden
DemoActiviti - SpringBootApplication
 @SpringBootApplication @ImportResource("classpath:activiti.cfg.xml") public class DemoActiviti { public static void main(String[] args) { Locale.setDefault(Locale.ENGLISH); SpringApplication.run(DemoActiviti.class, args); } } 


Ich verwende ein gemischtes Modell - wenn ein Teil der Beans in der XML-Konfiguration (@ImportResource ("classpath: activiti.cfg.xml")) beschrieben ist und der andere durch Anmerkungen definiert wird.

activiti.cfg.xml - Frühling
 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" /> <property name="driverClass" value="oracle.jdbc.driver.OracleDriver" /> <property name="username" value="BPM" /> <property name="password" value="1" /> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="databaseSchemaUpdate" value="true" /> <property name="asyncExecutorActivate" value="false" /> </bean> </beans> 


Jetzt ist Spring für die Konfiguration verantwortlich, wie man sehen kann

 bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration" 

Fügen Sie die Standardbefehlszeilenverarbeitung für SpringBoot als Komponente hinzu

Befehlszeile
 @Component public class CommandLine implements CommandLineRunner { @Autowired private DemoService demoService; public void run(String... args) { if ("test".equals(args[0])) { demoService.startTest(); } else if ("develop".equals(args[0])) { demoService.startDevelop(); } } } 


Was all diese Befehle verarbeiten wird, ich werde sie nicht alle implementieren, alles ist dort einfach, ich werde zwei zeigen: testen und entwickeln. Und fügen Sie einen Service hinzu, um sie zu verarbeiten

DemoService
 @Service public class DemoService { @Autowired private TaskService taskService; @Autowired private FormService formService; public void startTest() { List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("testers").list(); if (tasks.isEmpty()) { System.out.println("   "); return; } processTasks(tasks); } public void startDevelop() { List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("develop").list(); if (tasks.isEmpty()) { System.out.println("   "); return; } processTasks(tasks); } private void processTasks(List<Task> tasks) { Scanner scanner = new Scanner(System.in); for (Task task : tasks) { ......    ,  } 


In der CommandLine-Komponente Autowir verfügen sie über den DemoService-Dienst und darin über die bereits vorbereiteten Spring Activiti-Dienste

 @Autowired private TaskService taskService; 

Wir sammeln, laufen wie zuvor über die Kommandozeile.

Wenn Sie die Ausführung von Aufgaben aus dem Web verwenden möchten, verbinden Sie die REST-API.

REST-API


SpringBoot stellt standardmäßig einen eingebetteten Tomcat-Server und dann eine technische Angelegenheit zur Verfügung.
Fügen Sie in POM zu dem, was es ist, die Spring-Web-Abhängigkeit hinzu

  <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 

Wir entfernen die CommandLine-Komponente, jetzt kommt alles über die URL über HTTP. RestController hinzufügen:

Restcontroller
 @RestController public class DemoRestController { @Autowired private DemoService demoService; @RequestMapping(value="/test", method= RequestMethod.GET, produces= {MediaType.APPLICATION_JSON_VALUE}) public List<String> startTest(@RequestParam String devResult) { List<String> strings = demoService.startTest(devResult); return strings; } @RequestMapping(value="/develop", method= RequestMethod.GET, produces= MediaType.APPLICATION_JSON_VALUE) public List<String> startDevelop(@RequestParam String issue) { List<String> strings = demoService.startDevelop(issue); return strings; } @RequestMapping(value="/start", method= RequestMethod.GET, produces= MediaType.APPLICATION_JSON_VALUE) public List<String> startProcess() { List<String> strings = demoService.startDevProcess(); return strings; } } 


Wir führen dieselben Befehle aus und haben die Antworten des DemoService-Dienstes, den Autowire in der Steuerung hat, geringfügig geändert.

DemoService
 @Service public class DemoService { @Autowired private TaskService taskService; @Autowired private FormService formService; @Autowired private RuntimeService runtimeService; public List<String> startTest(String devResult) { List<String> results = new ArrayList<>(); List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("testers").list(); if (tasks.isEmpty()) { results.add("The tasks for testing are not"); return results; } Object issue = runtimeService.getVariables(tasks.get(0).getProcessInstanceId()).get("issue"); processTasks(tasks, devResult); results.add("Task N " + issue + " - tested, result=" + devResult); return results; } public List<String> startDevelop(String issue) { List<String> results = new ArrayList<>(); List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("programmers").list(); if (tasks.isEmpty()) { results.add("There are no development tasks"); return results; } processTasks(tasks, issue); Object mIssue = runtimeService.getVariables(tasks.get(0).getProcessInstanceId()).get("issue"); results.add("Task N " + mIssue + " - taken in the develop"); return results; } public List<String> startDevProcess() { List<String> results = new ArrayList<>(); ProcessInstance myProcess = runtimeService.startProcessInstanceByKey("devProcess"); results.add("The process is started #"+myProcess.getId()); return results; } private void processTasks(List<Task> tasks, String param) { for (Task task : tasks) { FormData formData = formService.getTaskFormData(task.getId()); Map<String, Object> variables = new HashMap<>(); //   for (FormProperty formProperty : formData.getFormProperties()) { variables.put(formProperty.getId(), param); } //   taskService.complete(task.getId(), variables); } } } 


Testen mit Curl, hier ist das Ergebnis:

Bild

Ich habe den Port für Tomcat in application.properties auf 8081 geändert
server.port = 8081

Activiti Job


Activiti hat viele Designs, zum Beispiel ist das Starten geplanter Aufgaben "TimerStartEvent". Damit Job in begrenztem Umfang ausgeführt werden kann, müssen Sie angeben
property name="asyncExecutorActivate" value="true" (siehe activiti.cfg.xml), dann läuft der Java-Prozess weiter und überprüft den Zeitplan und führt Aufgaben aus.

Ich werde zum ersten Projekt zurückkehren, in dem Activiti in seiner reinsten Form verwendet wird.

In der DemoActiviti-Klasse werde ich nur zwei Befehle unterstützen: Bereitstellen und Starten Ich werde einen neuen Prozess erstellen

Bild

Nach dem Start des Prozesses geht er zum Timer, der gemäß dem Zeitplan die Aufgabe „Entwickeln“ startet. Der Timer hat einen Zeitplan - Start alle 10 Sekunden, Cron-Ausdruck - "0/10 * * * * *?".

Bild

Lassen Sie uns den neuen Prozess wie zuvor bereitstellen und dann den Prozess starten (Start). Alle - Die Aufgabe wird alle 10 Sekunden ausgeführt.

Als Aufgabe wird die Activiti-Komponente ausgewählt - ServiceTask, aus der Sie als Java-Klassenimplementierung angeben können

Bild

Klasse DemoDelegate
 public class DemoDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) { Date now = new Date(); execution.setVariable("issue", now.toString()); System.out.println("job start="+now); } } 


In der Tabelle in der Datenbank (wählen Sie * aus ACT_RU_TIMER_JOB t) können Sie sehen

Bild

Jobaktivität, im Feld DUEDATE_ gibt es eine Zeit für den nächsten Start.

Die "Issue" -Variable des Delegaten wird im Ausführungsverlauf aufgezeichnet

 select * from ACT_HI_VARINST t 

Bild

Code für DemoActiviti c Job
 public class DemoActiviti { private static final String DEV_PROCESS = "devProcessJob"; public static void main(String[] args) { Locale.setDefault(Locale.ENGLISH); ProcessEngineConfiguration cfg = ProcessEngineConfiguration .createProcessEngineConfigurationFromResource("activiti.cfg.xml"); ProcessEngine processEngine = cfg.buildProcessEngine(); RepositoryService repositoryService = processEngine.getRepositoryService(); String mode = StringUtils.EMPTY; if (args.length > 0) { mode = args[0]; } System.out.println("Processes mode: " + mode); Deployment deployment; if ("deploy".equals(mode)) { deployment = repositoryService.createDeployment() .addClasspathResource("processes/MyProcessJob.bpmn").deploy(); System.out.println("deploy process success"); System.exit(0); } else { List<Deployment> myProcesses = repositoryService.createDeploymentQuery() .processDefinitionKey(DEV_PROCESS).list(); deployment = myProcesses.get(myProcesses.size()-1); System.out.println("get process success:" + deployment.getId()); } // RuntimeService runtimeService = processEngine.getRuntimeService(); ProcessInstance processInstance; if ("start".equals(mode)){ ProcessInstance myProcess = runtimeService.startProcessInstanceByKey(DEV_PROCESS); System.out.println("start process success:" + myProcess.getName() +", id="+ myProcess.getId()); } } } 


Es bleibt noch viel zurück: Events, Listener, JPA usw., vielleicht werde ich darauf zurückkommen.

Material
Activiti
Eclipse Designer

devProcess bpmn
 <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="devProcess" name="Dev process" isExecutable="true"> <startEvent id="startevent1" name="Start" activiti:initiator="programmerId"></startEvent> <userTask id="develop" name="Develop" activiti:candidateGroups="programmers"> <extensionElements> <activiti:formProperty id="issue" name="issue" type="string" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="develop"></sequenceFlow> <userTask id="test" name="Test" activiti:candidateGroups="testers"> <extensionElements> <activiti:formProperty id="devResult" name="devResult" type="string" default="No" required="true"></activiti:formProperty> </extensionElements> </userTask> <sequenceFlow id="flow2" sourceRef="develop" targetRef="test"></sequenceFlow> <exclusiveGateway id="gateway" name="Exclusive Gateway" default="flowNo"></exclusiveGateway> <sequenceFlow id="flow3" sourceRef="test" targetRef="gateway"></sequenceFlow> <sequenceFlow id="flowOk" name="Ok" sourceRef="gateway" targetRef="endevent1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${devResult == "Ok"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flowNo" name="No" sourceRef="gateway" targetRef="develop"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> </process> </definitions> 


devProcessJob bpmn
 <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="devProcessJob" name="Dev process Job" isExecutable="true"> <startEvent id="startevent" name="Start" activiti:initiator="programmerId"></startEvent> <sequenceFlow id="flow1" sourceRef="startevent" targetRef="timerstartevent"></sequenceFlow> <endEvent id="endevent" name="End"></endEvent> <startEvent id="timerstartevent" name="Timer start"> <extensionElements> <activiti:formProperty id="issue" name="issue" type="string"></activiti:formProperty> </extensionElements> <timerEventDefinition> <timeCycle>0/10 * * * * ?</timeCycle> </timerEventDefinition> </startEvent> <sequenceFlow id="flow2" sourceRef="timerstartevent" targetRef="servicetask1"></sequenceFlow> <sequenceFlow id="flow3" sourceRef="servicetask1" targetRef="endevent"></sequenceFlow> <serviceTask id="servicetask1" name="Develop" activiti:class="com.example.DemoDelegate"></serviceTask> </process> </definitions> 

Source: https://habr.com/ru/post/de416491/


All Articles