欧美一区二区三区视频免费_亚洲国产欧美一区二区丝袜黑人_一区二区三区资源_欧美一区二区视频免费观看

焦點(diǎn)速看:Springboot整合Camunda工作流引擎實(shí)現(xiàn)審批流程實(shí)例

環(huán)境:Spingboot2.6.14+camunda-spring-boot-starter7.18.0環(huán)境配置依賴配置7.18.0org.camunda

環(huán)境:Spingboot2.6.14 +camunda-spring-boot-starter7.18.0

環(huán)境配置

依賴配置


(資料圖片僅供參考)

7.18.0  org.camunda.bpm.springboot  camunda-bpm-spring-boot-starter-webapp  ${camunda.version}  org.camunda.bpm.springboot  camunda-bpm-spring-boot-starter-rest  ${camunda.version}

應(yīng)用程序配置

camunda.bpm:  webapp:    # 設(shè)置管理控制臺的訪問上下文    application-path: /workflow  auto-deployment-enabled: true  admin-user:    # 配置登錄管理控制臺的用戶    id: admin    password: admin    firstName: admin  filter:    create: All tasks  database:    #數(shù)據(jù)庫類型    type: mysql     #是否自動(dòng)更新表信息    schema-update: truelogging:  level:    #配置日志,這樣在開發(fā)過程中就能看到每步執(zhí)行的SQL語句了    "[org.camunda.bpm.engine.impl.persistence.entity]": debug---spring:  jersey:    application-path: /api-flow    type: servlet    servlet:      load-on-startup: 0

通過上面的配置后訪問控制臺:http://localhost:8100/workflow/

默認(rèn)是沒有上面的tasks中的內(nèi)容,這里是我之前測試數(shù)據(jù)

環(huán)境準(zhǔn)備好后,接下來就可以設(shè)計(jì)工作流程。

上面的camunda-bpm-spring-boot-starter-rest依賴中定義了一系列操作camunda的 rest api 這api的實(shí)現(xiàn)是通過jersey實(shí)現(xiàn),我們可以通過/api-flow前綴來訪問這些接口,具體有哪些接口,我們可以通過官方提供的camunda-bpm-run-7.18.0.zip

http://localhost:8080/swaggerui/#/

設(shè)計(jì)流程

這里設(shè)計(jì)兩個(gè)節(jié)點(diǎn)的審批流程,經(jīng)理審批---》人事審批 流程。

經(jīng)理審批節(jié)點(diǎn)

人事審批節(jié)點(diǎn)

上面配置了2個(gè)用戶任務(wù)節(jié)點(diǎn),并且為每個(gè)任務(wù)節(jié)點(diǎn)都設(shè)置了表達(dá)式,指定節(jié)點(diǎn)的審批人。

最終生成的流程XML內(nèi)容如下:

            Flow_18pxcpx                  Flow_18pxcpx      Flow_0n014x3                  Flow_0n014x3      Flow_0dsfy6s              Flow_0dsfy6s                                                                                                                                                                                          
部署流程

這里我不通過上面的rest api 進(jìn)行部署,而是通過自定義的接口然后調(diào)用camunda的相關(guān)api來實(shí)現(xiàn)流程部署。

上面的流程設(shè)計(jì)我是通過vue整合的camunda進(jìn)行設(shè)計(jì),并沒有使用官方提供的設(shè)計(jì)器。設(shè)計(jì)完成后直接上傳到服務(wù)端。

接口
@RestController@RequestMapping("/camunda")public class BpmnController {  // 上傳路徑  @Value("${gx.camunda.upload}")  private String path ;    // 通用的工作流操作api服務(wù)類  @Resource  private ProcessService processService ;    @PostMapping("/bpmn/upload")  public AjaxResult uploadFile(MultipartFile file, String fileName, String name) throws Exception {    try {      // 上傳并返回新文件名稱      InputStream is = file.getInputStream() ;      File storageFile = new File(path + File.separator + fileName) ;      FileOutputStream fos = new FileOutputStream(new File(path + File.separator + fileName)) ;      byte[] buf = new byte[10 * 1024] ;      int len = -1 ;      while((len = is.read(buf)) > -1) {        fos.write(buf, 0, len) ;      }      fos.close() ;      is.close() ;      // 創(chuàng)建部署流程      processService.createDeploy(fileName, name, new FileSystemResource(storageFile)) ;      return AjaxResult.success();    } catch (Exception e) {      return AjaxResult.error(e.getMessage());    }  }}
部署流程Service
// 這個(gè)是camunda spring boot starter 自動(dòng)配置@Resourceprivate RepositoryService repositoryService ;public void createDeploy(String resourceName, String name, org.springframework.core.io.Resource resource) {  try {    Deployment deployment = repositoryService.createDeployment()      .addInputStream(resourceName, resource.getInputStream())      .name(name)      .deploy();    logger.info("流程部署id: {}", deployment.getId());    logger.info("流程部署名稱: {}", deployment.getName());  } catch (IOException e) {    throw new RuntimeException(e) ;  }}

執(zhí)行上面的接口就能將上面設(shè)計(jì)的流程部署到camunda中(其實(shí)就是將流程文件保存到了數(shù)據(jù)庫中,對應(yīng)的數(shù)據(jù)表是:act_ge_bytearray)。

啟動(dòng)流程

啟動(dòng)流程還是一樣,通過我們自己的接口來實(shí)現(xiàn)。

接口
@RestController@RequestMapping("/process")public class ProcessController {  @Resource  private ProcessService processService ;    // 根據(jù)流程定義id,啟動(dòng)流程;整個(gè)流程需要?jiǎng)討B(tài)傳2個(gè)參數(shù)(審批人),如果不傳將會報(bào)錯(cuò)  @GetMapping("/start/{processDefinitionId}")  public AjaxResult startProcess(@PathVariable("processDefinitionId") String processDefinitionId) {    Map variables = new HashMap<>() ;    variables.put("uid", "1") ;    variables.put("mid", "1000") ;    processService.startProcessInstanceAssignVariables(processDefinitionId, "AKF", variables) ;    return AjaxResult.success("流程啟動(dòng)成功") ;  }}
服務(wù)Service接口
@Resourceprivate RuntimeService runtimeService ;public ProcessInstance startProcessInstanceAssignVariables(String processDefinitionId, String businessKey, Map variables) {  ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, businessKey, variables);  logger.info("流程定義ID: {}", processInstance.getProcessDefinitionId());  logger.info("流程實(shí)例ID: {}", processInstance.getId());  logger.info("BussinessKey: {}", processInstance.getBusinessKey()) ;  return processInstance ;}

流程啟動(dòng)后就可以查看當(dāng)前需要自己審批的所有審批單

接口實(shí)現(xiàn)
@Resourceprivate TaskService taskService ;@Resourceprivate ManagementService managementService ;// 根據(jù)時(shí)間段查詢public List queryTasksByBusinessAndCreateTime(String assignee, String businessKey, String startTime, String endTime) {  NativeTaskQuery nativeQuery = taskService.createNativeTaskQuery() ;  nativeQuery.sql("select distinct RES.* from " + managementService.getTableName(TaskEntity.class) +  " RES "                  + " left join " + managementService.getTableName(IdentityLinkEntity.class) + " I on I.TASK_ID_ = RES.ID_ "                  + " WHERE (RES.ASSIGNEE_ = #{assignee} or "                  + " (RES.ASSIGNEE_ is null and I.TYPE_ = "candidate" "                  + " and (I.USER_ID_ = #{assignee} or I.GROUP_ID_ IN ( #{assignee} ) ))) "                  + " and RES.CREATE_TIME_ between #{startTime} and #{endTime} "                  + " order by RES.CREATE_TIME_ asc LIMIT #{size} OFFSET 0") ;  nativeQuery.parameter("assignee", assignee) ;  nativeQuery.parameter("startTime", startTime) ;  nativeQuery.parameter("endTime", endTime) ;  nativeQuery.parameter("size", Integer.MAX_VALUE) ;  return nativeQuery.list() ;}
審批流程

流程啟動(dòng)后,接下來就是各個(gè)用戶任務(wù)節(jié)點(diǎn)配置的用戶進(jìn)行審批

接口
@GetMapping("/approve/{id}")public AjaxResult approve(@PathVariable("id") String instanceId) {  if (StringUtils.isEmpty(instanceId)) {    return AjaxResult.error("未知審批任務(wù)") ;  }  // 下面的參數(shù)信息應(yīng)該自行保存管理(與發(fā)起審批設(shè)置的指派人要一致)  Map variables = new HashMap<>() ;  // 第一個(gè)節(jié)點(diǎn)所要提供的遍歷信息(這里就是依次類推,mid等)  variables.put("uid", "1") ;  processService.executionTask(variables, instanceId, task -> {}, null) ;  return AjaxResult.success() ; }
服務(wù)Service接口
@Resourceprivate TaskService taskService ;@Resourceprivate RuntimeService runtimeService ;@Transactionalpublic void executionTask(Map variables, String instanceId, Consumer consumer, String type) {  Task task = taskService.createTaskQuery().processInstanceId(instanceId).singleResult() ;  if (task == null) {    logger.error("任務(wù)【{}】不存在", instanceId) ;    throw new RuntimeException("任務(wù)【" + instanceId + "】不存在") ;  }  taskService.setVariables(task.getId(), variables);  taskService.complete(task.getId(), variables) ;  long count = runtimeService.createExecutionQuery().processInstanceId(instanceId).count();  if (count == 0) {    consumer.accept(task) ;  }}

以上就完成了從整個(gè)流程的生命周期:

設(shè)計(jì)流程---》部署流程---》啟動(dòng)流程---》審批流程

完畢!!!

關(guān)鍵詞:
責(zé)任編輯:hn1007
主站蜘蛛池模板: 91免费精品视频| 97精品视频在线播放| 日本午夜在线亚洲.国产| 不卡中文字幕av| 国产精品精品视频| 国产精品96久久久久久| 欧日韩免费视频| 国产精品免费观看高清| 午夜精品一区二区三区视频免费看| 欧美亚洲另类在线一区二区三区| 蜜臀精品一区二区| 在线一区亚洲V| 欧美在线视频二区| 日本视频一区在线观看| 国产综合av一区二区三区| 日韩精品视频一区二区在线观看 | 日韩久久不卡| 国产精品久久久久久久久免费| 国产精品美女在线播放| 精品国产依人香蕉在线精品| 国产99久久久欧美黑人| 久久久久久久免费视频| 日韩视频在线观看视频| 国模吧一区二区| 日韩精品综合在线| 深夜福利日韩在线看| 91精品在线国产| 岛国一区二区三区高清视频| 宅男在线精品国产免费观看| 99国产精品白浆在线观看免费| 国产一区免费视频| 久久久久久久免费| 国产精品美女久久久免费| 国产精品一区二区在线观看| 国产一区二区视频免费在线观看| 久久99精品久久久久久久青青日本 | 一区二区三区四区久久| 国产成人精品日本亚洲11| 久久精品五月婷婷| 国产精品一区在线免费观看 | 亚洲最新免费视频|