业务需求:创建一个简易审批流程,在流程结束时,用执行监听器,在监听器内遵循RPC 使用规约,远程调用另一个服务的业务进行数据入库操作

步骤一:建立新模块,并在新模块中遵循 yudao-cloud文档 微服务手册 服务调用 Feign中示例,建立api接口、实现类、监听器


API:

package cn.iocoder.yudao.module.tr.api.coursetitleform;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.tr.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = ApiConstants.NAME) // ① @FeignClient 注解
@Tag(name = "RPC 服务 - 课题") // ② Swagger 接口文档
public interface CourseTitleFormApi {

    String PREFIX = ApiConstants.PREFIX + "/course-title-form";

    @PostMapping(PREFIX + "/add") // ③ Spring MVC 接口注解
    @Operation(summary = "通过用户 ID 查询用户")  // ② Swagger 接口文档
    @Parameter(name = "id", description = "部门编号", required = true, example = "1024") // ② Swagger 接口文档
    CommonResult<Long> create(
            @RequestParam("projectType") String projectType,
            @RequestParam("courseNo") Long courseNo,
            @RequestParam("courseName") String courseName,
            @RequestParam("researchDirection") String researchDirection,
            @RequestParam("principal") String principal,
            @RequestParam("principalDegree") String principalDegree,
            @RequestParam("titleForFunds") String titleForFunds,
            @RequestParam("directFunds") String directFunds,
            @RequestParam("indirectFunds") String indirectFunds,
            @RequestParam("startTime") String startTime, // 建议使用字符串形式传输时间
            @RequestParam("endTime") String endTime,
            @RequestParam("fileUrl") String fileUrl
    );
}

这里有个坑,不能用@RequestBody接参,否则会出现重复读取InputStream报错:java.lang.IllegalStateException: getInputStream() has already been called for this request 

原因可参考:spring mvc处理http请求报错:java.lang.IllegalStateException: getInputStream() has already been called for this request - 不想下火车的人 - 博客园

接口实现:
 

package cn.iocoder.yudao.module.tr.service.coursetitleform;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.tr.api.coursetitleform.CourseTitleFormApi;
import cn.iocoder.yudao.module.tr.api.coursetitleform.dto.CourseTitleFormRespDTO;
import cn.iocoder.yudao.module.tr.controller.admin.coursetitleform.vo.CourseTitleFormSaveReqVO;
import cn.iocoder.yudao.module.tr.dal.dataobject.coursetitleform.CourseTitleFormDO;
import cn.iocoder.yudao.module.tr.dal.mysql.coursetitleform.CourseTitleFormMapper;
import cn.iocoder.yudao.module.tr.utils.DateUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

import static org.bouncycastle.asn1.cmc.CMCStatus.success;

/**
 * @author 16050
 * @date 2025/7/21 14:11
 * @description TODO
 */
@RestController
@Validated
public class CourseTitleFormApiImpl implements CourseTitleFormApi {

    @Resource
    private CourseTitleFormMapper courseTitleFormMapper;

    @Override
    public CommonResult<Long> create(
            String projectType,
            Long courseNo,
            String courseName,
            String researchDirection,
            String principal,
            String principalDegree,
            String titleForFunds,
            String directFunds,
            String indirectFunds,
            String startTime,
            String endTime,
            String fileUrl
    ) {
        // 构造保存 VO
        CourseTitleFormSaveReqVO createReqVO = new CourseTitleFormSaveReqVO();
        createReqVO.setProjectType(projectType);
        createReqVO.setCourseNo(courseNo);
        createReqVO.setCourseName(courseName);
        createReqVO.setResearchDirection(researchDirection);
        createReqVO.setPrincipal(principal);
        createReqVO.setPrincipalDegree(principalDegree);
        createReqVO.setTitleForFunds(titleForFunds);
        createReqVO.setDirectFunds(directFunds);
        createReqVO.setIndirectFunds(indirectFunds);
        createReqVO.setStartTime(DateUtils.parseLocalDateTime(startTime)); // 字符串转 LocalDateTime
        createReqVO.setEndTime(DateUtils.parseLocalDateTime(endTime));
        createReqVO.setFileUrl(fileUrl);

        // 保存数据
        CourseTitleFormDO courseTitleForm = BeanUtils.toBean(createReqVO, CourseTitleFormDO.class);
        courseTitleFormMapper.insert(courseTitleForm);

        return CommonResult.success(courseTitleForm.getId());
    }
}


bpm中监听器:

package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.tr;


import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.tr.api.coursetitleform.CourseTitleFormApi;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author 16050
 * @date 2025/7/19 16:25
 * @description TODO
 */

@Component("courseSubmitListener") // 指定 Bean 名称
@Slf4j
public class CourseSubmitListener implements JavaDelegate {

    @Resource
    private CourseTitleFormApi courseTitleFormApi;

    public void execute(DelegateExecution execution) {
        try {
            String projectType = (String) execution.getVariable("projectType");
            String courseNo = (String) execution.getVariable("courseNo");
            String startTime = (String) execution.getVariable("startTime");
            String courseTitleName = (String) execution.getVariable("courseTitleName");
            String researchDirection = (String) execution.getVariable("researchDirection");
            String principal = (String) execution.getVariable("principal");
            String principalDegree = (String) execution.getVariable("principalDegree");
            String titleForFunds = (String) execution.getVariable("titleForFunds");
            String directFunds = (String) execution.getVariable("directFunds");
            String indirectFunds = (String) execution.getVariable("indirectFunds");
            String endTime = (String) execution.getVariable("endTime");
            String fileUrl = (String) execution.getVariable("fileUrl");
            if (fileUrl == null) {
                fileUrl = ""; // 或者给个默认值,比如 null
            }


            String startDateTimeStr = startTime + " 00:00:00";
            String endDateTimeStr = endTime + " 23:59:59";


            // 直接调用 Feign 方法(注意:必须传字符串,接口签名定义的就是字符串)
            CommonResult<Long> result = courseTitleFormApi.create(
                    projectType,
                    Long.valueOf(courseNo),
                    courseTitleName,
                    researchDirection,
                    principal,
                    principalDegree,
                    titleForFunds,
                    directFunds,
                    indirectFunds,
                    startDateTimeStr,  // 字符串传入即可
                    endDateTimeStr,
                    fileUrl
            );


            if (result.isSuccess()) {
                log.info("[流程监听] 课题创建成功,ID={}", result.getData());
            } else {
                log.error("[流程监听] 课题创建失败,错误消息: {}", result.getMsg());
            }
        } catch (Exception e) {
            log.error("[流程监听] 课题创建异常", e);
        }
    }

}

步骤二:建立流程,并引入监听器
流程:


这里一定要用全局的执行监听器,不然会重复调用两次监听器。

表单:
中记得设置字段ID,监听器中会通过这个ID来取值,如之前监听器中写的(String) execution.getVariable("projectType");


监听器:

这里用代理表达式,和监听器中的@Component("courseSubmitListener")名称一致

更多推荐