跳转到内容

Flow/Function 批量处理

业务场景

业务开发中经常会遇到需要批量修改数据的场景,比如批量上下架商品,批量修改商品分类和上架时间等等。

Trantor 针对这种批量处理场景提供了机制和扩展能力,使用方法请查看下文。

使用示例

  1. 后端定义一个批量处理的Function,如下:
@Function(name = "batch update company info")
public interface BatchUpdateCompanyFunc {
List<Company> execute(QCompany qCompany, Company updateCompany);
}
@FunctionImpl(name = "批量修改公司信息")
public class BatchUpdateCompanyFuncImpl implements BatchUpdateCompanyFunc {
@Override
public List<Company> execute(QCompany qCompany, Company updateCompany) {
List<Company> companyList = DS.findAll(qCompany);
for (Company company : companyList) {
if (Objects.nonNull(updateCompany.getName())) company.setName(updateCompany.getName());
if (Objects.nonNull(updateCompany.getShortName())) company.setShortName(updateCompany.getShortName());
if (Objects.nonNull(updateCompany.getAbbreviation())) company.setAbbreviation(updateCompany.getAbbreviation());
if (Objects.nonNull(updateCompany.getAddress())) company.setAddress(updateCompany.getAddress());
if (Objects.nonNull(updateCompany.getStatus())) company.setStatus(updateCompany.getStatus());
if (Objects.nonNull(updateCompany.getRemark())) company.setRemark(updateCompany.getRemark());
}
DS.update(companyList);
return companyList;
}
}

由于上面的BatchUpdateCompanyFunc是声明在erp业务域下,所以可以得到资源 key 为erp_BatchUpdateCompanyFunc

批量处理的Flow/Function的参数必须符合以下要求:

  • 第一个参数必须存在,且声明为查询模型QModel

    • 主要携带了当前页面的过滤信息,包含table组件上的搜索区域信息,condition/dataCondition信息,dataPrarams信息等会影响数据结果的条件过滤信息;
    • QModel可以帮助我们在后续逻辑里查询出目标数据进行批量操作,如下:
    // 根据前端条件过滤条件,查询目标数据记录,方便后续对这些数据做批量处理
    List<Company> companyList = DS.findAll(qCompany);
  • 第二个参数可选择声明,主要作为载体用于接收前端批量处理的信息,如果不填,则接收不到修改的信息,在某个简单批量处理场景可能存在,比如批量启用/停用,则不需要前端传递复杂信息,因为启用/停用可能就是修改个状态信息,前端传不传不重要,比如:

    • 启用公司信息
    @FunctionImpl(name = "启用公司信息")
    public class BatchEnableCompanyFuncImpl implements BatchEnableCompanyFunc {
    @Override
    public void execute(QCompany qCompany) {
    List<Company> companyList = DS.findAll(qCompany);
    companyList.forEach(company -> company.setStatus(CompanyStatus.enable));
    DS.update(companyList);
    }
    • 停用公司信息
    @FunctionImpl(name = "停用公司信息")
    public class BatchDisableCompanyFuncImpl implements BatchDisableCompanyFunc {
    @Override
    public void execute(QCompany qCompany) {
    List<Company> companyList = DS.findAll(qCompany);
    companyList.forEach(company -> company.setStatus(CompanyStatus.disable));
    DS.update(companyList);
    }
    }
  1. 定义前端视图

    • dataCondition/DataStore 数据源
    <?xml version="1.0" encoding="UTF-8"?>
    <View menuView="true" type="List" forModel="erp_Company" title="公司列表" version="2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://terminus-trantor.oss-cn-hangzhou.aliyuncs.com/xsi/0.18.x/base.xsd">
    <Table key="table" allowCheckAll="#{true}" model="erp_Company" dataCondition="">
    <Search>
    <Fields>
    <Field name="name" label="公司名称"/>
    <Field name="shortName" label="公司简称"/>
    <Field name="status" label="状态"/>
    </Fields>
    </Search>
    <Fields>
    <Field name="name" label="公司名称"/>
    <Field name="code" label="公司编码"/>
    <Field name="shortName" label="公司简称"/>
    <Field name="abbreviation" label="公司缩写"/>
    <Field name="address" label="地址"/>
    <Field name="remark" label="公司详情"/>
    <Field name="status" label="状态"/>
    </Fields>
    <RecordActions label="操作">
    <Action label="详情" targetView="erp_Company_CompanyDetails"/>
    <Action label="编辑" targetView="erp_Company_CompanyEdit"/>
    <Action type="Delete" label="删除" after="Refresh" logicFunction="erp_DeleteCompanyBuiltInFunc" confirm="确定删除吗?"/>
    </RecordActions>
    <Actions>
    <Action label="批量启用" batch="true" logicFunction="erp_BatchEnableCompanyFunc" after="Refresh"/>
    <Action label="批量禁用" batch="true" logicFunction="erp_BatchDisableCompanyFunc" after="Refresh"/>
    <Action label="批量更新" batch="true" targetView="erp_Company_CompanyBatchUpdate" openViewType="Dialog"/>
    <Action label="新建公司" targetView="erp_Company_CompanyCreate"/>
    </Actions>
    </Table>
    </View>
    • dataFlow/dataFunc 数据源
    <?xml version="1.0" encoding="UTF-8"?>
    <View menuView="true" type="List" forModel="erp_Company" title="公司列表" version="2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://terminus-trantor.oss-cn-hangzhou.aliyuncs.com/xsi/0.18.x/base.xsd">
    <Table key="table" allowCheckAll="#{true}" model="erp_Company" dataFunc="erp_PagingCompanyBuiltInFunc">
    <Search>
    <Fields>
    <Field name="name" label="公司名称"/>
    <Field name="shortName" label="公司简称"/>
    <Field name="status" label="状态"/>
    </Fields>
    </Search>
    <Fields>
    <Field name="name" label="公司名称"/>
    <Field name="code" label="公司编码"/>
    <Field name="shortName" label="公司简称"/>
    <Field name="abbreviation" label="公司缩写"/>
    <Field name="address" label="地址"/>
    <Field name="remark" label="公司详情"/>
    <Field name="status" label="状态"/>
    </Fields>
    <RecordActions label="操作">
    <Action label="详情" targetView="erp_Company_CompanyDetails"/>
    <Action label="编辑" targetView="erp_Company_CompanyEdit"/>
    <Action type="Delete" label="删除" after="Refresh" logicFunction="erp_DeleteCompanyBuiltInFunc" confirm="确定删除吗?"/>
    </RecordActions>
    <Actions>
    <Action label="批量启用" batch="#{true}" logicFunction="erp_BatchEnableCompanyFunc" after="Refresh"/>
    <Action label="批量禁用" batch="#{true}" logicFunction="erp_BatchDisableCompanyFunc" after="Refresh"/>
    <Action label="批量更新" batch="#{true}" targetView="erp_Company_CompanyBatchUpdate" openViewType="Dialog"/>
    <Action label="新建公司" targetView="erp_Company_CompanyCreate"/>
    </Actions>
    </Table>
    </View>

    核心代码是:

    <Action label="批量更新" batch="#{true}" targetView="erp_Company_CompanyBatchUpdate" openViewType="Dialog"/>
    • 批量处理操作必须使用batch="#{true}"声明Action,这样才能在 table 左侧看到勾选框
    • targetView="erp_Company_CompanyBatchUpdate"指向批量修改信息的表单视图
  2. 批量修改的表单页

    视图资源 key 为erp_Company_CompanyBatchUpdate

    <?xml version="1.0" encoding="UTF-8"?>
    <View xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://terminus-trantor.oss-cn-hangzhou.aliyuncs.com/xsi/0.18.x/base.xsd"
    version="2" type="Form" forModel="erp_Company" title="批量修改公司信息">
    <Form model="erp_Company">
    <Fields>
    <Field name="name" label="公司名称"/>
    <Field name="shortName" label="公司简称"/>
    <Field name="abbreviation" label="公司缩写"/>
    <Field name="address" label="地址"/>
    <Field name="status" label="状态"/>
    <Field name="remark" label="公司详情"/>
    </Fields>
    <Actions>
    <Action type="Submit" batch="#{true}" label="提交" after="GoBack" logicFunction="erp_BatchUpdateCompanyFunc"/>
    </Actions>
    </Form>
    </View>
  • batch="#{true}"logicFunction="xxx"同时声明在Action表示按钮将触发批量处理行为,logicFlow="xxx"同理:

    • 如果声明了batch="#{true}",则Action点击事件将请求批量处理Flow/Function接口
      • flow: /api/trantor/batch/flow/{flowKey}
      • function: /api/batch/trantor/func/{funcKey}
    • 如果未声明batch="#{true}"batch="#{false}",则Action点击事件将请求原来的 Flow/Function 接口
      • flow: /api/trantor/flow/{flowKey}
      • function: /api/trantor/func/{funcKey}
  • logicFunction="erp_BatchUpdateCompanyFunc"声明批量处理的目标Function

权限限制

功能权限

批量处理的batchFlow/batchFunc跟原生的Flow/Func对于功能权限具有相同特性,都可以受权限管理控制

数据权限

行数据权限

在查询视图模型数据和批量处理时,需要关注数据源的dataCondition/dataFlow/dataFunc和批量处理的batchFlow/batchFunc是否具有一致的行数据权限状态,这将影响到视图展示数据和批量处理的目标数据的一致性,举个例子:

  • 现有订单模型数据共五条,id=[1,2,3,4,5],用户 A 配置了订单模型的行数据权限为只能查询id小于或等于3的订单记录,即SQL = select * from tb_order where id <= 3

  • 用户 A 查看的订单列表视图使用dataFunc查询数据,并且开启了行数据权限,查询结果即为id=[1,2,3]共三条模型记录;

  • 批量处理的batchFunc未开启行数据权限,使用QModel查询订单模型数据时查询到的结果则为id=[1,2,3,4,5],这时候的批量处理将导致数据越权。

列数据权限

目前trantor对于列数据的处理都是在接口出口在返回数据时根据列数据权限规则移除数据中受限的数据列,以此实现列数据过滤;

批量处理场景应该没有需要处理返回数据的需求,所以也不需要对返回数据做列数据权限过滤。