En guide til Activiti med Java

1. Oversigt

Activiti API er et workflow- og Business Process Management-system. Vi kan definere en proces i den, udføre den og manipulere den på forskellige måder ved hjælp af de tjenester, der leveres af API'en. Det kræver JDK 7+.

Udvikling ved hjælp af API kan gøres i enhver IDE, men for at bruge Activiti Designer har vi brug for Eclipse.

Vi kan definere en proces i den ved hjælp af BPMN 2.0-standarden. Der er en anden, mindre populær måde - ved hjælp af Java-klasser som StartEvent, EndEvent, UserTask, SekvensFlow, etc.

Hvis vi vil køre en proces eller få adgang til nogen af ​​tjenesterne, skal vi oprette en ProcessEngineConfiguration.

Vi kan få ProcessEngine ved brug af ProcessEngineConfiguration, på nogle måder, som vi vil diskutere yderligere i denne artikel. igennemdet ProcessEngine vi kan udføre Workflow- og BPMN-operationer.

2. Maven-afhængigheder

For at bruge denne API skal vi medtage Activiti-afhængighed:

 org.activiti aktiviti-motor 

3. Oprettelse af en ProcessEngine

ProcessEngine i Activiti er typisk konfigureret ved hjælp af en XML-fil, aktiviti.cfg.xml. Et eksempel på denne konfigurationsfil er:

Nu kan vi få ProcessEngine bruger ProcessEngines klasse:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine ();

Denne erklæring vil se efter en aktiviti.cfg.xml-fil i klassestien, og konstruer en ProcessEngine baseret på konfigurationen i filen.

Eksempelkoden til konfigurationsfilen viser, at den kun er en fjederbaseret konfiguration. Men det betyder ikke, at vi kun kan bruge Activiti i et forårsmiljø. Forårsfunktionerne bruges bare internt til at skabe ProcessEngine.

Lad os skrive en JUnit test case, der vil skabe ProcessEngine ved hjælp af konfigurationsfilen vist ovenfor:

@Test offentlig ugyldighed givetXMLConfig_whenGetDefault_thenGotProcessEngine () {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine (); assertNotNull (processEngine); assertEquals ("root", processEngine.getProcessEngineConfiguration () .getJdbcUsername ()); } 

4. Activiti Process Engine API og tjenester

Indgangsstedet for interaktion med API'en er ProcessEngine. Gennem ProcessEngine, vi kan få adgang til forskellige tjenester, der leverer workflow / BPMN-metoder. Det ProcessEngine og alle serviceobjekter er trådsikre.

Hentet fra //www.activiti.org/userguide/images/api.services.png

Det ProcessEngines klasse scanner efter aktiviti.cfg.xml og activiti-context.xml filer. Som nævnt tidligere, for alle de aktiviti.cfg.xml filer, ProcessEngine vil blive oprettet på en typisk måde.

Der henviser til, for alle activiti-context.xml filer, oprettes det på foråret - jeg opretter Spring Application Context og vil hente ProcessEngine fra det. Under udførelsen af ​​en proces vil alle trin blive besøgt i den rækkefølge, der er defineret i BPMN-filen.

Under udførelsen af ​​en proces vil alle trin blive besøgt i den rækkefølge, der er defineret i BPMN-filen.

4.1. Processdefinition og relaterede vilkår

EN ProcessDefinition repræsenterer en forretningsproces. Det bruges til at definere strukturen og opførslen af ​​forskellige trin i processen. Implementering af en procesdefinition betyder indlæsning af procesdefinitionen i Activiti-databasen.

Processdefinitioner er for det meste defineret af BPMN 2.0-standarden. Det er også muligt at definere dem ved hjælp af Java-kode. Alle udtryk defineret i dette afsnit er også tilgængelige som Java-klasser.

Når vi begynder at køre en procesdefinition, kan den kaldes en proces

EN ProcessInstance er en udførelse af en ProcessDefinition.

EN StartEvent er forbundet med enhver forretningsproces. Det angiver startpunktet for processen. Tilsvarende er der en EndEvent hvilket indikerer afslutningen på processen. Vi kan definere betingelser over disse begivenheder.

Alle trin (eller elementer) mellem start og slut kaldes Opgaver. Opgaver kan være af forskellige typer. De mest anvendte opgaver er Brugeropgaver og Serviceopgaver.

Brugeropgaver, som navnet antyder, er sådan, at de skal udføres manuelt af en bruger.

Serviceopgaverpå den anden side er konfigureret med et stykke kode. Når udførelsen når dem, vil deres blok af kode blive udført.

SekvensFlows forbinde Opgaver. Vi kan definere SekvensFlows af kilde- og målelementerne, som de forbinder. Igen kan vi også definere betingelser over SekvensFlows at skabe betingede stier i processen.

4.2. Tjenester

Vi diskuterer kort de tjenester, der leveres af Activiti:

  • RepositoryService hjælper os med at manipulere implementeringen af ​​procesdefinitioner. Denne service beskæftiger sig med de statiske data relateret til en procesdefinition
  • RuntimeService administrerer ProcessStoffer (kører i øjeblikket processer) såvel som procesvariablerne
  • TaskService holder styr på Brugeropgaver. Det Opgaver der skal udføres manuelt af en bruger, er kernen i Activiti API. Vi kan oprette en opgave, kræve og fuldføre en opgave, manipulere tildelingen af ​​opgaven osv. Ved hjælp af denne service
  • FormService er en valgfri tjeneste. API'en kan bruges uden den og uden at ofre nogen af ​​dens funktioner. Det bruges til at definere startformularen og opgaveformularen i en proces.
  • IdentityService administrerer Brugere og Grupper
  • HistoryService holder styr på historien om Activiti Engine. Vi kan også indstille forskellige historieniveauer.
  • ManagementService er relateret til metadataene og kræves normalt ikke, når du opretter en applikation
  • DynamicBpmnService hjælper os med at ændre noget i en proces uden at omplacere det

5. Arbejde med Activiti Services

For at lære, hvordan vi kan arbejde med forskellige tjenester og køre en proces, lad os tage et eksempel på en proces for "Medarbejderferieanmodning":

BPMN 2.0-filen, VacationRequest.bpmn20.xml, for denne proces vil startbegivenheden være defineret som:

Tilsvarende vil den første brugeropgave, der er tildelt brugergruppen "ledelse", se sådan ud:

 $ {medarbejdernavn} vil gerne tage $ {numberOfDays} dag (er) med ferie (motivation: $ {årsag}). ledelse 

Med Serviceopgave, vi er nødt til at definere det stykke kode, der skal udføres. Vi har dette stykke kode som en Java-klasse:

Den betingede strøm vises ved at tilføje “ConditionExpression” tag i "SekvensFlow":

Her, ferieGodkendt er formEjendom af UserTask vist ovenfor.

Som vi kan se i diagrammet, er det en meget enkel proces. Medarbejderen fremsætter en ferieanmodning med antal dage og startdatoen for ferien. Anmodningen går til lederen. De kan godkende / afvise anmodningen.

Hvis godkendt, er der defineret en serviceopgave til at sende bekræftelses-e-mailen. Hvis afvist, kan medarbejderen enten vælge at ændre og sende anmodningen igen eller ikke gøre noget.

Serviceopgaver leveres med et stykke kode, der skal udføres (her som en Java-klasse). Vi har givet klassen SendEmailServiceTask.java.

Disse typer klasser skal udvide JavaDelegate. Vi er også nødt til at tilsidesætte dens udføre () metode, som udføres, når procesudførelsen når dette trin.

5.1. Implementering af en proces

For at gøre vores proces kendt for Activiti Engine er vi nødt til at implementere processen. Vi kan gøre det programmatisk ved hjælp af RepositoryService. Lad os skrive en JUnit-test for at vise dette:

@Test offentlig ugyldighed givenBPMN_whenDeployProcess_thenDeployed () {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine (); RepositoryService repositoryService = processEngine.getRepositoryService (); repositoryService.createDeployment () .addClasspathResource ("org / activiti / test / vacationRequest.bpmn20.xml") .deploy (); Langt antal = repositoryService.createProcessDefinitionQuery (). Count (); assertEquals ("1", count.toString ()); }

Implementering betyder, at motoren vil analysere BPMN-filen og konvertere den til noget eksekverbart. Der tilføjes også en post til repository-tabellen for hver implementering.

Derfor kan vi bagefter spørge Datalager service for at få de implementerede processer det Processdefinitioner.

5.2. Start af en ProcessInstance

Efter indsættelse af ProcessDefinition til Activiti Engine, kan vi udføre processen ved at oprette ProcessStoffer. Det ProcessDefinition er en plan, og ProcessInstance er runtime-udførelsen af ​​det.

For en enkelt ProcessDefinition, der kan være flere ProcessStoffer.

Alle detaljer relateret til ProcessStoffer kan tilgås via RuntimeService.

I vores eksempel skal vi ved startbegivenheden videregive antallet af feriedage, startdatoen og årsagen. Vi bruger procesvariablerne og videregiver dem, mens vi opretter ProcessInstance.

Lad os skrive en JUnit test case for at få en bedre idé:

@Test offentlig ugyldighed givenDeployedProcess_whenStartProcessInstance_thenRunning () {// implementere procesdefinitionen Kortvariabler = ny HashMap> (); variables.put ("medarbejdernavn", "John"); variables.put ("numberOfDays", 4); variables.put ("vacationMotivation", "Jeg har brug for en pause!"); RuntimeService runtimeService = processEngine.getRuntimeService (); ProcessInstance processInstance = runtimeService .startProcessInstanceByKey ("vacationRequest", variabler); Langt antal = runtimeService.createProcessInstanceQuery (). Count (); assertEquals ("1", count.toString ()); }

De flere forekomster af en enkelt procesdefinition vil variere efter procesvariablerne.

Der er flere måder at starte en procesinstans på. Her bruger vi nøglen til processen. Efter start af procesforekomsten kan vi få oplysningerne om det ved at spørge RuntimeService.

5.3. Afslutning af opgaver

Når vores procesforekomst begynder at køre, er det første trin en brugeropgave, der er tildelt brugergruppen "ledelse".

Brugeren kan have en indbakke, der har en liste over opgaver, der skal udføres af dem. Hvis vi nu vil fortsætte procesudførelsen, skal brugeren afslutte denne opgave. For Activiti Engine kaldes det "at fuldføre opgaven".

Vi kan spørge TaskService, for at hente opgaveobjektet og derefter fuldføre det.

Koden, vi skal skrive til dette, ser ud som:

@Test offentlig ugyldighed givenProcessInstance_whenCompleteTask_thenGotNextTask () {// implementere proces og starte procesinstans TaskService taskService = processEngine.getTaskService (); Listeopgaver = taskService.createTaskQuery () .taskCandidateGroup ("management"). Liste (); Opgaveopgave = opgaver.get (0); Kort taskVariables = nyt HashMap (); taskVariables.put ("vacationApproved", "false"); taskVariables.put ("kommentarer", "Vi har en stram deadline!"); taskService.complete (task.getId (), taskVariables); Opgave currentTask = taskService.createTaskQuery () .taskName ("Rediger ferieanmodning"). SingleResult (); assertNotNull (nuværende opgave); }

Bemærk, at komplet() metode til TaskService tager også de krævede procesvariabler ind. Vi sender svaret fra lederen.

Herefter fortsætter procesmotoren til næste trin. Her spørger det næste trin medarbejderen, om ferieanmodningen skal sendes igen eller ej.

Så vores ProcessInstance venter nu på dette UserTask, som har navnet “Rediger ferie anmodning".

5.4. Suspendering og aktivering af en proces

Vi kan suspendere en ProcessDefinition og også en ProcessInstance. Hvis vi suspenderer en Processdefinition, vi kan ikke oprette en forekomst af den, mens den er suspenderet. Vi kan gøre dette ved hjælp af RepositoryService:

@Test (forventet = ActivitiException.class) offentlig ugyldighed givenDeployedProcess_whenSuspend_thenNoProcessInstance () {// implementere procesdefinition repositoryService.suspendProcessDefinitionByKey ("vacationRequest"); runtimeService.startProcessInstanceByKey ("vacationRequest"); } 

For at aktivere det igen skal vi bare ringe til et af repositoryService.activateProcessDefinitionXXX metoder.

På samme måde kan vi suspendere a ProcessInstance, bruger RuntimeService.

6. Konklusion

I denne artikel så vi, hvordan vi kunne bruge Activiti med Java. Vi oprettede en prøve ProcessEngineCofiguration fil, som hjælper os med at oprette ProcessEngine.

Ved hjælp af det fik vi adgang til forskellige tjenester leveret af API'en. Disse tjenester hjælper os med at styre og holde styr på Processdefinitioner, ProcessStoffer, Brugeropgaver, etc.

Som altid ligger koden til eksempler, vi så i artiklen, på GitHub.