Flowable7.x学习笔记(十一)分页查询已部署 BPMN XML 流程定义明细

前言

        上一篇文章我们完成了部署后的基础信息分页查询,但是不能在这里直接激活流程,因为会有多个版本信息,所以我们这篇文章再来完成明细信息分页查询功能。

一、基础代码生成

        自动生成步骤请参照:操作演示

① 实体类

package com.ceair.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 流程部署定义信息表
 * </p>
 *
 * @author wangbaohai
 * @since 2025-04-20
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("ACT_RE_PROCDEF")
public class ActReProcdef implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    @TableId(value = "ID_", type = IdType.ASSIGN_ID)
    private String id;

    @TableField("REV_")
    private Integer rev;

    @TableField("CATEGORY_")
    private String category;

    @TableField("NAME_")
    private String name;

    @TableField("KEY_")
    private String key;

    @TableField("VERSION_")
    private Integer version;

    @TableField("DEPLOYMENT_ID_")
    private String deploymentId;

    @TableField("RESOURCE_NAME_")
    private String resourceName;

    @TableField("DGRM_RESOURCE_NAME_")
    private String dgrmResourceName;

    @TableField("DESCRIPTION_")
    private String description;

    @TableField("HAS_START_FORM_KEY_")
    private Integer hasStartFormKey;

    @TableField("HAS_GRAPHICAL_NOTATION_")
    private Integer hasGraphicalNotation;

    @TableField("SUSPENSION_STATE_")
    private Integer suspensionState;

    @TableField("TENANT_ID_")
    private String tenantId;

    @TableField("ENGINE_VERSION_")
    private String engineVersion;

    @TableField("DERIVED_FROM_")
    private String derivedFrom;

    @TableField("DERIVED_FROM_ROOT_")
    private String derivedFromRoot;

    @TableField("DERIVED_VERSION_")
    private Integer derivedVersion;


}

② mapper 接口

package com.ceair.mapper;

import com.ceair.entity.ActReProcdef;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * <p>
 * 流程部署定义信息表 Mapper 接口
 * </p>
 *
 * @author wangbaohai
 * @since 2025-04-20
 */
@Mapper
public interface ActReProcdefMapper extends BaseMapper<ActReProcdef> {

}

③ 服务

package com.ceair.service;

import com.ceair.entity.ActReProcdef;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 * 流程部署定义信息表 服务类
 * </p>
 *
 * @author wangbaohai
 * @since 2025-04-20
 */
public interface IActReProcdefService extends IService<ActReProcdef> {

}

④ 服务实现

package com.ceair.service.impl;

import com.ceair.entity.ActReProcdef;
import com.ceair.mapper.ActReProcdefMapper;
import com.ceair.service.IActReProcdefService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wangbaohai
 * @since 2025-04-20
 */
@Service
public class ActReProcdefServiceImpl extends ServiceImpl<ActReProcdefMapper, ActReProcdef> implements IActReProcdefService {

}

⑤ XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ceair.mapper.ActReProcdefMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.ceair.entity.ActReProcdef">
        <id column="ID_" property="id" />
        <result column="REV_" property="rev" />
        <result column="CATEGORY_" property="category" />
        <result column="NAME_" property="name" />
        <result column="KEY_" property="key" />
        <result column="VERSION_" property="version" />
        <result column="DEPLOYMENT_ID_" property="deploymentId" />
        <result column="RESOURCE_NAME_" property="resourceName" />
        <result column="DGRM_RESOURCE_NAME_" property="dgrmResourceName" />
        <result column="DESCRIPTION_" property="description" />
        <result column="HAS_START_FORM_KEY_" property="hasStartFormKey" />
        <result column="HAS_GRAPHICAL_NOTATION_" property="hasGraphicalNotation" />
        <result column="SUSPENSION_STATE_" property="suspensionState" />
        <result column="TENANT_ID_" property="tenantId" />
        <result column="ENGINE_VERSION_" property="engineVersion" />
        <result column="DERIVED_FROM_" property="derivedFrom" />
        <result column="DERIVED_FROM_ROOT_" property="derivedFromRoot" />
        <result column="DERIVED_VERSION_" property="derivedVersion" />
    </resultMap>

    <sql id="Base_Column_List">
        ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_,
        RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_,
        HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_,
        ENGINE_VERSION_, DERIVED_FROM_, DERIVED_FROM_ROOT_, DERIVED_VERSION_
    </sql>

</mapper>

二、后端:分页查询功能

① 创建请求参数

package com.ceair.entity.request;

import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * @author wangbaohai
 * @ClassName QueryActReProcdefReq
 * @description: 分页查询流程部署明细信息请求对象
 * @date 2025年04月21日
 * @version: 1.0.0
 */
@Data
public class QueryActReProcdefReq implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    /**
     * 页面请求参数-流程名
     */
    private String processName;

    /**
     * 页面请求对象,用于封装分页查询的相关参数。
     * 该对象通常包含页码、每页记录数等信息,用于在分页查询时传递给服务层或数据访问层。
     */
    private PageReq pageReq;

}

② 创建响应参数VO

package com.ceair.entity.vo;

import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

/**
 * @author wangbaohai
 * @ClassName ActReProcdefVO
 * @description: 流程部署明细信息VO
 * @date 2025年04月21日
 * @version: 1.0.0
 */
@Data
public class ActReProcdefVO implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    private String id;

    private Integer rev;

    private String category;

    private String name;

    private String key;

    private Integer version;

    private String deploymentId;

    private String resourceName;

    private String dgrmResourceName;

    private String description;

    private Integer hasStartFormKey;

    private Integer hasGraphicalNotation;

    private Integer suspensionState;

    private String tenantId;

    private String engineVersion;

    private String derivedFrom;

    private String derivedFromRoot;

    private Integer derivedVersion;

}

③ 创建模型转换工具

package com.ceair.utils;

import com.ceair.entity.ActReProcdef;
import com.ceair.entity.vo.ActReProcdefVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

/**
 * @author wangbaohai
 * @ClassName ActReProcdefStructMapper
 * @description: 流程部署定义信息结构映射器
 * @date 2025年04月21日
 * @version: 1.0.0
 */
@Mapper
public interface ActReProcdefStructMapper {

    /**
     * Mapper接口,用于在{@link ActReProcdef}和{@link ActReProcdefVO}之间进行转换。
     * 该接口提供了将实体映射为值对象以及将值对象映射为实体的方法。
     */
    ActReProcdefStructMapper INSTANCE = Mappers.getMapper(ActReProcdefStructMapper.class);

    /**
     * 将{@link ActReProcdef}实体对象转换为其对应的{@link ActReProcdefVO}值对象。
     *
     * @param actReProcdef 要转换的{@link ActReProcdef}实体对象,不能为空。
     * @return 转换后的{@link ActReProcdefVO}值对象。
     * @throws IllegalArgumentException 如果输入参数'actReProcdef'为空,则抛出异常。
     */
    default ActReProcdefVO toVO(ActReProcdef actReProcdef) {
        // 验证输入参数是否为空
        if (actReProcdef == null) {
            throw new IllegalArgumentException("输入参数'actReProcdef'不能为空。");
        }
        return mapToVO(actReProcdef);
    }

    /**
     * 将{@link ActReProcdef}实体对象映射为其对应的{@link ActReProcdefVO}值对象。
     *
     * @param actReProcdef 要映射的{@link ActReProcdef}实体对象。
     * @return 映射后的{@link ActReProcdefVO}值对象。
     */
    ActReProcdefVO mapToVO(ActReProcdef actReProcdef);

    /**
     * 将{@link ActReProcdefVO}值对象转换为其对应的{@link ActReProcdef}实体对象。
     *
     * @param actReProcdefVO 要转换的{@link ActReProcdefVO}值对象,不能为空。
     * @return 转换后的{@link ActReProcdef}实体对象。
     * @throws IllegalArgumentException 如果输入参数'actReProcdefVO'为空,则抛出异常。
     */
    default ActReProcdef toEntity(ActReProcdefVO actReProcdefVO) {
        // 验证输入参数是否为空
        if (actReProcdefVO == null) {
            throw new IllegalArgumentException("输入参数'actReProcdefVO'不能为空。");
        }
        return mapToEntity(actReProcdefVO);
    }

    /**
     * 将{@link ActReProcdefVO}值对象映射为其对应的{@link ActReProcdef}实体对象。
     *
     * @param actReProcdefVO 要映射的{@link ActReProcdefVO}值对象。
     * @return 映射后的{@link ActReProcdef}实体对象。
     */
    ActReProcdef mapToEntity(ActReProcdefVO actReProcdefVO);


}

④ 创建服务

/**
 * 分页查询流程定义信息。
 *
 * @param queryActReProcdefReq 查询条件请求对象,包含分页信息和筛选条件。
 *            该对象通常包括页码、每页大小以及可能的过滤字段(如流程定义名称、状态等)。
 * @return 返回一个分页结果对象,包含符合条件的流程定义信息。
 *         结果类型为 Page<ActReProcdef>,其中 ActReProcdef 表示流程定义的实体类,
 *         Page 表示分页封装类,通常包含数据列表、总记录数等信息。
 */
Page<ActReProcdef> queryActReProcdefWithPage(QueryActReProcdefReq queryActReProcdefReq);

⑤ 创建服务实现

/**
 * 分页查询流程定义基础信息。
 *
 * @param queryActReProcdefReq 查询请求对象,包含分页参数和查询条件。
 *                             如果为 null 或其分页参数为空,则使用默认分页参数(第一页,每页10条数据)。
 * @return 返回一个分页对象 Page<ActReProcdef>,包含查询结果和分页信息。
 * 如果查询过程中发生异常,则抛出 BusinessException。
 */
@Override
public Page<ActReProcdef> queryActReProcdefWithPage(QueryActReProcdefReq queryActReProcdefReq) {
    // 初始化分页工具以及参数,默认为第一页,每页10条数据
    long current = 1;
    long size = 10;

    // 检查请求对象及其分页参数是否为空,并根据需要设置分页参数
    if (queryActReProcdefReq != null && queryActReProcdefReq.getPageReq() != null) {
        current = queryActReProcdefReq.getPageReq().getCurrent() > 0 ?
                queryActReProcdefReq.getPageReq().getCurrent() : current;
        size = queryActReProcdefReq.getPageReq().getSize() > 0 ? queryActReProcdefReq.getPageReq().getSize() : size;
    }

    // 初始化分页对象,用于存储分页查询结果
    Page<ActReProcdef> page = new Page<>(current, size);

    // 调用 mapper 进行分页查询,捕获可能的异常并记录日志
    try {
        return this.baseMapper.queryActReProcdefWithPage(page, queryActReProcdefReq);
    } catch (Exception e) {
        // 捕获异常并记录日志,避免系统崩溃
        log.error("查询流流程定义基础信息分页失败,请求参数: {}", queryActReProcdefReq, e);
        throw new BusinessException("查询流程定义基础信息分页失败,请稍后重试", e);
    }
}

⑥ 创建自定义SQL

<sql id="Base_Column_List">
    ID_, REV_, CATEGORY_, NAME_, KEY_, VERSION_, DEPLOYMENT_ID_,
    RESOURCE_NAME_, DGRM_RESOURCE_NAME_, DESCRIPTION_, HAS_START_FORM_KEY_,
    HAS_GRAPHICAL_NOTATION_, SUSPENSION_STATE_, TENANT_ID_,
    ENGINE_VERSION_, DERIVED_FROM_, DERIVED_FROM_ROOT_, DERIVED_VERSION_
</sql>

<select id="queryActReProcdefWithPage" resultMap="BaseResultMap">
    SELECT <include refid="Base_Column_List" /> FROM ACT_RE_PROCDEF
    <where>
        <if test="queryActReProcdefReq.processName != null and queryActReProcdefReq.processName != ''">
            AND NAME_ LIKE CONCAT('%', #{queryActReProcdefReq.processName}, '%')
        </if>
    </where>
</select>

⑦ 创建接口

private final IActReProcdefService actReProcdefService;

/**
 * 分页查询流程部署定义信息。
 *
 * @param queryActReProcdefReq 流程部署定义信息查询请求对象,包含分页和过滤条件等信息,不能为空。
 * @return 包含流程部署定义信息的分页结果对象,其中数据为视图对象(VO)列表。
 * 如果查询或转换失败,则返回错误信息。
 * <p>
 * 功能描述:
 * 1. 调用服务层方法查询流程部署定义信息,并返回分页结果。
 * 2. 将查询结果中的记录转换为视图对象(VO)列表。
 * 3. 返回包含转换后列表和总记录数的分页结果对象。
 * 4. 捕获并记录查询或转换过程中的异常,返回错误信息。
 */
@PreAuthorize("hasAnyAuthority('/api/v1/actReProcdef/page')")
@Parameter(name = "queryActReProcdefReq", description = "流程部署定义信息查询请求对象", required = true)
@Operation(summary = "分页查询流程部署定义信息")
@PostMapping("/page")
public PageResult<List<ActReProcdefVO>> queryActReProcdefWithPage(@RequestBody QueryActReProcdefReq queryActReProcdefReq) {
    try {
        // 调用服务层方法查询流程部署定义信息,并返回分页结果
        Page<ActReProcdef> page = actReProcdefService.queryActReProcdefWithPage(queryActReProcdefReq);

        // 将查询结果中的记录转换为视图对象(VO)列表
        List<ActReProcdefVO> list =
                Optional.ofNullable(page.getRecords()).orElse(Collections.emptyList()).parallelStream().map(record -> {
                    try {
                        // 使用映射器将实体对象转换为视图对象
                        return ActReProcdefStructMapper.INSTANCE.toVO(record);
                    } catch (Exception e) {
                        // 记录转换失败的错误信息
                        log.error("转换流程部署定义信息失败 具体原因为 : {}", e.getMessage());
                        return null;
                    }
                }).filter(Objects::nonNull).toList();

        // 返回包含转换后列表和总记录数的分页结果对象
        return PageResult.success(list, page.getTotal());
    } catch (Exception e) {
        // 记录查询失败的错误信息,并返回错误结果
        log.error("查流程部署定义信息失败 具体原因为 : {}", e.getMessage());
        return PageResult.error("查询流程部署定义信息失败:" + e.getMessage());
    }
}

三、前端:完成分页查询功能

① 创建参数

// 分页请求参数
export interface PageReq {
  current: number // 当前页码,默认值为 1
  size: number // 每页显示记录数,默认值为 10
}

// 分页查询流程部署定义请求对象
export interface QueryActReProcdefReq {
  processName: string // 页面请求参数-流程名称
  pageReq: PageReq // 分页请求对象,包含页码、每页记录数等信息
}

export interface ActReProcdefVO {
  id: string // 主键ID (Java String)
  rev: number // 修订版本号 (Java Integer)
  category: string // 类别 (Java String)
  name: string // 名称 (Java String)
  key: string // 流程 Key (Java String)
  version: number // 版本号 (Java Integer)
  deploymentId: string // 部署 ID (Java String)
  resourceName: string // 资源名称 (Java String)
  dgrmResourceName: string // 流程图资源名称 (Java String)
  description: string // 描述 (Java String)
  hasStartFormKey: number // 是否有启动表单 (Java Integer)
  hasGraphicalNotation: number// 是否含图形标注 (Java Integer)
  suspensionState: number // 挂起状态 (Java Integer)
  tenantId: string // 租户 ID (Java String)
  engineVersion: string // 引擎版本 (Java String)
  derivedFrom: string // 来源部署 ID (Java String)
  derivedFromRoot: string // 根来源部署 ID (Java String)
  derivedVersion: number // 来源版本号 (Java Integer)
}

② 创建接口

import type { QueryActReProcdefReq } from './actReProcdefType'
import request from '@/utils/http/request'

// 分页查询部署定义信息
export function pageActReProcdef(data: QueryActReProcdefReq) {
  return request.post<any>({
    url: '/pm-process/api/v1/actReProcdef/page',
    data,
  })
}

③ 创建查询界面

<script lang="ts" setup>
import type { ActReProcdefVO, QueryActReProcdefReq } from '@/api/actReProcdef/actReProcdefType'
import { pageActReProcdef } from '@/api/actReProcdef/actReProcdefApi'

import useLayoutStore from '@/store/modules/setting'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'

// 使用layout组件小仓库
const layoutStore = useLayoutStore()

// 定义响应式数据 processName 收集查询条件的流程名称
const processName = ref('')
// 定义响应式数据 currentPage 收集当前页码
const currentPage = ref<number>(1)
// 定义响应式数据 pageSize 收集每页显示的条数
const pageSize = ref<number>(10)
// 定义响应式数据 total 收集总数据条数
const total = ref<number>(0)
// 定义响应式数据 actReDeploymentList 表示流程定义列表
const actReProcdefList = ref<ActReProcdefVO[]>([])
// 表格列定义
const tableColumns = [
  { label: '#', type: 'index', align: 'center', width: '50px' },
  { label: 'ID', prop: 'id', align: 'center' },
  { label: '定义类型', prop: 'category', align: 'center' },
  { label: '定义名称', prop: 'name', align: 'center' },
  { label: '定义Key', prop: 'key', align: 'center' },
  { label: '定义版本', prop: 'version', align: 'center' },
  { label: '部署ID', prop: 'deploymentId', align: 'center' },
  { label: '资源名称', prop: 'resourceName', align: 'center' },
  { label: '图片名称', prop: 'dgrmResourceName', align: 'center' },
  { label: '定义状态', prop: 'suspensionState', align: 'center' },
]

// 定义状态字典
const suspensionStateDict: Record<number, string> = {
  1: '激活',
  2: '挂起',
}

/**
 * onMounted 生命周期钩子函数
 *
 * 在组件挂载完成后执行以下操作:
 * 1. 初始化分页参数和流程名称。
 * 2. 调用函数获取流程定义的分页数据。
 *
 * @param {Function} onMounted - Vue 的生命周期钩子函数,无需传参。
 * @returns {void} 无返回值。
 */
onMounted(() => {
  // 初始化分页参数:当前页为第一页,每页显示10条数据
  currentPage.value = 1
  pageSize.value = 10

  // 初始化流程名称为空字符串
  processName.value = ''

  // 调用函数获取流程定义的分页数据
  getActReProcdefPageData()
})

/**
 * 获取流程定义分页数据的异步函数。
 *
 * @function getActReProcdefPageData
 * @description 该函数用于组装分页查询参数,调用后端接口获取流程定义数据,并处理查询结果或异常。
 *
 * @param {void} - 无参数。
 * @returns {Promise<void>} - 无返回值,但会更新流程定义列表和总记录数,或在失败时显示错误消息。
 */
async function getActReProcdefPageData() {
  try {
    // 组装分页查询参数,包含部署名称和分页信息
    const queryParams: QueryActReProcdefReq = {
      processName: processName.value,
      pageReq: {
        current: currentPage.value,
        size: pageSize.value,
      },
    }

    // 调用分页查询接口,获取流程定义数据
    const result: any = await pageActReProcdef(queryParams)

    // 判断查询结果是否成功,成功则更新流程列表和总记录数
    if (result.success && result.code === 200) {
      actReProcdefList.value = result.data
      // 翻译字典 actReProcdefList中的每个元素的suspensionState字段 挂起状态(1=激活,2=挂起)
      actReProcdefList.value.forEach((item: any) => {
        item.suspensionState = suspensionStateDict[item.suspensionState]
      })

      total.value = result.total
    }
  }
  catch (error) {
    // 捕获异常并提取错误信息
    let errorMessage = '未知错误'
    if (error instanceof Error) {
      errorMessage = error.message
    }

    // 显示异常错误消息
    ElMessage({
      message: `查询失败: ${errorMessage || '未知错误'}`,
      type: 'error',
    })
  }
}

// 重置查询条件
function resetQuery() {
  layoutStore.refresh = !layoutStore.refresh
}

/**
 * 处理页面数据的函数。
 * 该函数调用获取流程定义页面数据的方法。
 *
 * @function handerPageData
 */
function handerPageData() {
  // 调用获取流程定义页面数据的函数
  getActReProcdefPageData()
}
</script>

<template>
  <!-- 查询条件区域 -->
  <el-card style="height: 75px;">
    <el-form :inline="true" class="form-inline">
      <el-form-item label="流程定义名称">
        <el-input
          v-model.trim="processName"
          placeholder="请输入流程定义名称"
          maxlength="50"
          show-word-limit
        />
      </el-form-item>
      <el-form-item>
        <el-button v-hasButton="`btn.actReProcdef.page`" type="primary" icon="Search" @click="getActReProcdefPageData">
          查询
        </el-button>
        <el-button icon="Refresh" @click="resetQuery">
          重置
        </el-button>
      </el-form-item>
    </el-form>
  </el-card>

  <!-- 查询结果列表区域 -->
  <el-card style="margin: 10px 0px;">
    <el-table style="margin: 10px 0px;" :border="true" :data="actReProcdefList">
      <!-- ID 区域 -->
      <el-table-column type="selection" align="center" width="50px" />
      <!-- 表格数据 区域 -->
      <el-table-column
        v-for="(column, index) in tableColumns"
        :key="index"
        :type="column.type"
        :label="column.label"
        :prop="column.prop"
        :align="column.align"
        :width="column.width"
      />
    </el-table>
    <!-- 分页器 -->
    <el-pagination
      v-model:current-page="currentPage"
      v-model:page-size="pageSize"
      :page-sizes="[10, 20, 30, 40, 50]"
      layout="prev, pager, next, jumper,->, sizes, total"
      :total="Math.max(total, 0)"
      @current-change="getActReProcdefPageData"
      @size-change="handerPageData"
    />
  </el-card>
</template>

<style scoped>
.form-inline {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap; /* 适配小屏幕 */
}
</style>

四、配置权限

① 增加菜单

② 增加按钮

③ 分配权限

五、查询结果展示

六、后记

本篇文章的前后端仓库地址请查询专栏第一篇文章

本文的后端分支是 process-5

本文的前端分支是 process-7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值