数据集事件

数据集提供了查询数据、插入/更新数据和删除数据的方法,同时提供了执行这些方法的前后事件。用于查询、插入/更新和删除数据时,实现一些扩展需求。

例如下面这几个场景:

  • 在采购表中插入一条采购数据时,要同时更新库存表中的数据
  • 在更新用户表的用户姓名后,更新其他表里面存储的用户姓名
  • 在删除一个商品分类后,将商品表中的商品分类清空
  • 在《数据集参数》一节中讲到的,使用输出参数对手机号进行脱敏的能力,可以使用本节介绍的方法实现,在查询数据后,对数据进行处理,最后将处理后的数据返回前端

也适用于以下几个场景:

  • 插入/更新A表信息前,进行逻辑判断是否可以操作,如果不可以操作更新失败并且失败内容提醒用户
  • 插入/更新A表之后需要更新B表,操作失败进行事务回滚
  • 插入/更新A表前,需要查询其他补充A表的其他字段内容,再进行插入A表

系统提供的数据集事件,是在代码层使用 Spring Event 事件发布/监听机制实现的。并且数据集事件和方法在同一个事务内。

下面以调用数据集的插入/更新数据方法为例,说明执行方法和事件的执行过程。

  • 在前端发送插入/更新数据的请求
  • 系统派发一个事件,事件中的参数有服务名、模块名、数据集标识、数据表名、状态(执行开始)、插入/更新的数据等信息,在事件中设置是否已经处理完毕(默认 false)
    • 未处理完,系统执行插入/更新数据方法
      • 如果插入/更新成功,系统派发一个事件,事件中的参数有服务名、模块名、数据集标识、数据表名、状态(执行成功)等信息
      • 如果插入/更新失败,系统派发一个事件,事件中的参数有服务名、模块名、数据集标识、数据表名、状态(执行失败)等信息
    • 已处理完,不再执行插入/更新数据方法,这种方式也称为全接管,即只执行开发者的代码,不执行系统的方法

添加数据集事件

增加依赖设置

引入系统工具类

组名称 名称 版本号
com.justep tools 1.0.0

增加数据集事件处理类

在 service 目录下,新增 java 文件,例如:EventHandler.java。

增加 @Component 注解

使用 @Component 方式实现 Spring Event,在 class 前面添加 @Component 注解,代码如下:

@Component
public class EventHandler {
}

使用 condition 进行过滤

condition 中的条件使用 event 属性任意组合,支持并且和或者。在 java 方法前面,添加 @EventListener(condition = "#event.属性 == 值"),用来区分是谁发起的事件,代码如下:

@EventListener(condition = "#event.moduleName == 'main' && #event.dataModelName == 'buy' && #event.method == 'upsert'")
public void upsertStore(DbUpsertEvent event) throws Exception {

}

表示来自 main 模块、buy 数据集的插入/更新方法会触发本事件。

判断事件的状态

在执行动作时,事件会触发两次,第一次的 status 为 START,第二次的 status 为 SUCCEED 或 FAILED,状态为枚举类型:

public enum Status {
    START, SUCCEED, FAILED
}

使用下面的代码判断事件的状态是否为 START:

if(event.getStatus()==Status.START)

插入/更新的事件

事件参数

插入/更新事件的参数为 DbUpsertEvent 类,构造方法如下:

public DbUpsertEvent(JSONObject request, JSONArray data, Connection conn, String service, String tableName, String dataModelName, List<String> conditionFields) {
    super(METHOD_UPSERT, request, conn, service, tableName, dataModelName, conditionFields, null, null);
    this.data = data;
}

部分接管案例

案例:插入/更新采购表,更新库存表

采购表 buy,包括主键 fid,用品 goods,数量 num 列 库存表 store,包括主键 fid,用品 goods,库存数 num 列 采购表的 goods 和库存表的 goods 对应,插入/更新采购表,则使用 goods 更新库存表 代码如下:

    @Autowired
    BuyMapperPlus mapperBuy;
    @Autowired
    StoreMapperPlus mapperStore;

    @EventListener(condition="#event.tableName=='main_buy' && #event.method=='upsert' && #event.moduleName=='main'")
    public void upsertStore(DbUpsertEvent event) throws Exception {
        if(event.getStatus()!=Status.START) return;
        //获取服务名
        String serviceName = ContextUtil.getServiceName();
        //获取插入/更新的数据
        JSONArray data = event.getData();
        for(int i=0;i<data.size();i++) {
            JSONObject row = data.getJSONObject(i);
            String fid = row.getString("fid");
            String goods = row.getString("goods");
            Integer num = row.getInteger("num");

            //使用《2.3.2 java SDK》一节中介绍的系统提供的方法查询库存表
            DbrestWrapper<?> wrapperStore = (DbrestWrapper<?>)new DbrestWrapper<String>(serviceName, "main", "store");
            wrapperStore.eq("goods",goods);
            List<Store> listStore = DbrestUtil.selectList(wrapperStore, Store.class);

            //也可以使用mybatisPlus的方法查询采购表
            QueryWrapper<Buy> wrapperBuy = new QueryWrapper<>();
            wrapperBuy.eq("fid",fid);
            List<Buy> listBuy = mapperBuy.selectList(wrapperBuy);

            //计算更新前的数量
            Integer oldNum = 0;
            if(listBuy.size()>0) {
                oldNum = listBuy.get(0).getNum();
                if(oldNum == null) {
                    oldNum = 0;
                }
            }

            //更新库存表,也可以使用mybatis的方法更新
            Store store = new Store();
            if(listStore.size()==0) {
                store.setFid(RandomUtil.uuid());
                store.setGoods(goods);
                store.setNum(num - oldNum);
                store.setVersion(0);
            }else {
                Store s = listStore.get(0);
                store.setFid(s.getFid());
                store.setNum(s.getNum() + num - oldNum);
                store.setVersion(s.getVersion() + 1);
            }

            List<Store> storeList = new ArrayList<Store>();
            storeList.add(store);
            DbrestResult ret = DbrestUtil.upsert(serviceName, "main", "store", storeList);
        }
    }

全接管案例

同时更新多张表(全接管,返回 handled=true)

客户表 customer,包括主键 fid、客户名 name,销售员ID salerID 列 销售员表 saler,包括主键 fid、姓名 name、手机号 phone 列 添加一个 sql 数据集 customerSaler,关联查询客户表和销售员表。sql 数据集可以更新到一张表,通过事件更新另一张表,也可以不使用 sql 数据集的更新到一张表,通过事件更新两张表。本例采用后者,代码如下:

    @EventListener(condition="#event.dataModelName=='customerSaler' && #event.method=='upsert' && #event.moduleName=='main'")
    public void upsertMutilTable(DbUpsertEvent event) throws Exception {
        if(event.getStatus()!=Status.START) return;
        //获取服务名
        String serviceName = ContextUtil.getServiceName();
        //获取插入/更新的数据
        JSONArray data = event.getData();
        List<Saler> salerList = new ArrayList<Saler>();

        for(int i=0;i<data.size();i++) {
            //获得销售员数据
            JSONObject row = data.getJSONObject(i);
            String salerId = row.getString("salerID");
            String salerName = row.getString("saler_name");
            String salerPhone = row.getString("saler_phone");

            //获取销售员表的数据
            DbrestWrapper<?> wrapperSaler = (DbrestWrapper<?>)new DbrestWrapper<String>(serviceName, "main", "saler");
            wrapperSaler.eq("fid",salerId);
            List<Saler> listSaler = DbrestUtil.selectList(wrapperSaler, Saler.class);

            //修改销售员表的数据
            if(listSaler.size()>0) {
                Saler saler = new Saler();
                Saler s = listSaler.get(0);
                saler.setFid(s.getFid());
                saler.setName(salerName);
                saler.setPhone(salerPhone);
                salerList.add(saler);  
            }

        }
        //更新销售员表
        DbrestResult ret = DbrestUtil.upsert(serviceName, "main", "saler", salerList);

        //插入/更新客户表
        List<UpsertWrappers<Customer>> list = DbrestUtil.createUpsertWrappers(event, Customer.class);
        int i=0;
        for (UpsertWrappers<Customer> wrappers: list) {
            List<Customer> obj = mapperCustomer.selectList(wrappers.getQueryWrapper());
            if (obj != null && obj.size() > 0) {
                i += mapperCustomer.update(wrappers.getEntity(), wrappers.getQueryWrapper());
            } else {
                mapperCustomer.insert(wrappers.getEntity());
            }
        }
        //准备返回数据
        JSONObject json = new JSONObject();
        json.put("status", 200);
        json.put("result", "total:" + list.size() + ", updated:" + i);
        json.put("eventHandled", true);
        event.setResult(json);//设置返回数据
        event.setHandled(true);//设置全接管
    }

删除数据的事件

事件参数

删除事件的参数为 DbDeleteEvent 类,构造方法如下:

public DbDeleteEvent(JSONObject request, JSONArray data, Connection conn, String service, String tableName, String dataModelName, List<String> conditionFields, List<String> conditionOperations, List<Object> paramValues) {
    super(METHOD_DELETE, request, conn, service, tableName, dataModelName, conditionFields, conditionOperations, paramValues);
    this.data = data;
}

案例

删除采购表数据,更新库存表。删除事件中可以获得删除数据的主键,根据主键获取数据,修改库存表的库存数,代码如下:

    @EventListener(condition="#event.tableName=='main_buy' &&  #event.method=='delete' && #event.moduleName=='main'")
    public void deleteStore(DbDeleteEvent event) throws Exception {
        if(event.getStatus()!=Status.START) return;
        String serviceName = ContextUtil.getServiceName();
        //获取采购表的数据
        QueryWrapper<Buy> wrapperBuy = DbrestUtil.createDeleteQueryWrapper(event);
        List<Buy> listBuy = mapperBuy.selectList(wrapperBuy);

        for(int i=0;i<listBuy.size();i++) {
            Buy row = listBuy.get(i);
            String fid = row.getFid();
            String goods = row.getGoods();
            Integer num = row.getNum();

            //获取库存表的数据
            DbrestWrapper<?> wrapperStore = (DbrestWrapper<?>)new DbrestWrapper<String>(serviceName, "main", "store");
            wrapperStore.eq("goods",goods);
            List<Store> listStore = DbrestUtil.selectList(wrapperStore, Store.class);

            //减去库存数
            Store store = new Store();
            if(listStore.size()>0) {
                Store s = listStore.get(0);
                store.setFid(s.getFid());
                store.setNum(s.getNum() - num);
                store.setVersion(s.getVersion() + 1);
            }

            //更新到库存表
            List<Store> storeList = new ArrayList<Store>();
            storeList.add(store);
            DbrestResult ret = DbrestUtil.upsert(serviceName, "main", "store", storeList);
        }
    }

查询数据的事件

事件参数

查询事件的参数为 DbQueryEvent 类,构造方法如下:

public DbQueryEvent(JSONObject request, Connection conn, String service, String tableName, String dataModelName, long offset, long limit, String queryField, List<String> conditionFields, List<String> conditionOperations, List<Object> paramValues) {
    super(METHOD_QUERY, request, conn, service, tableName, dataModelName, conditionFields, conditionOperations, paramValues);
    this.queryField = queryField;
    this.offset = offset;
    this.limit = limit;
}

案例

修改查询返回的数据。在查询事件中,获取查询结果数据,修改后返回,代码如下:

    @EventListener(condition="#event.tableName=='main_buy' && #event.method=='query' && #event.moduleName=='main'")
    public void queryBuy(DbQueryEvent event) throws Exception {
        if(event.getStatus()!=Status.START) return;
        //获得查询结果数据
        QueryWrapper<Buy> wrapper = new QueryWrapper<>();
        DbrestUtil.fillQueryWrapper(wrapper, event);
        List<Buy> list = mapperBuy.selectList(wrapper);

        //修改查询结果数据
        for(int i=0;i<list.size();i++) {
            list.get(i).setPrice(new BigDecimal(99));
        }

        //返回查询结果数据
        JSONObject json = new JSONObject();
        json.put("status", 200);
        json.put("result", JSON.toJSONString(list));
        json.put("eventHandled", true);
        event.setResult(json);//设置返回数据
        event.setHandled(true);//设置全接管
    }

results matching ""

    No results matching ""