최근 진행한 프로젝트에서 승인 모듈을 구현해야 했는데, 이를 위해 Flowable을 선택했습니다.
아래는 Flowable의 기본 사용 방법에 대한 소개입니다.
프로세스 구현
1. 의존성 추가
<!-- Flowable 의존성 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.2</version>
</dependency>
2. 프로세스 다이어그램 생성
여기서는 IDEA의 Flowable BPMN visualizer 플러그인을 사용합니다.
bpmn20.xml 파일 생성
플러그인을 이용한 프로세스 다이어그램 작성
- bpmn20.xml 파일을 우클릭합니다
- 플러그인을 사용하여 프로세스를 시각화합니다
- 필요한 요소들을 다이어그램에 추가합니다
다이어그램 작성이 완료되면, bpmn20.xml 파일에 내용이 자동으로 생성됩니다.
컨트롤러 구현
package com.example.workflow.controller;
import com.example.workflow.common.ResultVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Task;
import org.flowable.engine.*;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 휴가 승인 컨트롤러
*/
@RestController
@RequestMapping("/approval")
@Slf4j
@Api(value = "휴가 승인 API", tags = "휴가 승인 API")
public class ApprovalController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
/**
* 휴가 승인 프로세스 생성
* @param employeeId 직원 ID
* @param employeeName 직원 이름
* @param leaveDays 휴가 일수
* @param reason 휴가 사유
* @return 생성 결과
*/
@PostMapping("create")
@ApiOperation("휴가 승인 프로세스 생성")
public ResultVo<String> createApprovalRequest(
@RequestParam("employeeId") Integer employeeId,
@RequestParam("employeeName") String employeeName,
@RequestParam("leaveDays") Integer leaveDays,
@RequestParam("reason") String reason) {
Map<String, Object> variables = new HashMap<>();
variables.put("employeeId", employeeId);
variables.put("employeeName", employeeName);
variables.put("leaveDays", leaveDays);
variables.put("reason", reason);
// 프로세스 인스턴스 시작
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveApproval", variables);
log.info("프로세스 변수: {}", variables);
return ResultVo.success("휴가 신청이 접수되었습니다. 프로세스 ID: " + processInstance.getId());
}
/**
* 프로세스 다이어그램 조회
* @param response HTTP 응답 객체
* @param processId 프로세스 ID
* @throws 예외 처리
*/
@GetMapping("diagram")
@ApiOperation("프로세스 다이어그램 조회")
public void getProcessDiagram(HttpServletResponse response, @RequestParam("processId") String processId) throws Exception {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processId)
.singleResult();
if (processInstance == null) {
return;
}
Task currentTask = taskService.createTaskQuery()
.processInstanceId(processInstance.getId())
.singleResult();
// 현재 실행 중인 작업 조회
List<Execution> executions = runtimeService
.createExecutionQuery()
.processInstanceId(currentTask.getId())
.list();
}
/**
* 휴가 승인 처리
* @param taskId 작업 ID
* @param approvalDecision 승인 여부 (true: 승인, false: 거절)
* @return 처리 결과
*/
@PostMapping("decision")
@ApiOperation("휴가 승인/거절 처리")
public ResultVo<String> processApprovalDecision(
@RequestParam("taskId") String taskId,
@RequestParam("approvalDecision") Boolean approvalDecision) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
return ResultVo.success("존재하지 않는 승인 요청입니다");
}
// 승인 변수 설정
Map<String, Object> variables = new HashMap<>();
variables.put("approvalResult", approvalDecision);
// 작업 완료 처리
taskService.complete(taskId, variables);
return ResultVo.success("승인 처리가 완료되었습니다. 결과: " + (approvalDecision ? "승인" : "거절"));
}
}