多级单据体通过缓存实现-父子孙三级原创
金蝶云社区-豹
12人赞赏了该文章 1,465次浏览 未经作者许可,禁止转载编辑于2022年03月24日 17:45:54

背景:

苍穹本身已经支持两级单据体功能,即单据体与子单据体,该需求为要基于子单据体再建一个“孙”单据体,在子单据体中点击不同的行在“孙”单据体中显示对应的数据。


实现效果:

2022.03.24-17.34.36 00_00_00-00_00_30.gif


主要关注点:

该需求充添加第二级子单据体为起始,进行的一系列操作

  1. 将选择的多行子单据体的数据回调填入到孙单据体中

  2. 在填充和转义数据时候顺便把数据存储到缓存,并建立各个数据包的关系,把数据关系也存储到缓存(比如第一级包含哪些第二级数据的id,用map的数据格式存储下来;第二级和第三级的关系也是这样存储的)

  3. 在添加第三级孙数据时也把数据添加到缓存(我这里是在拿二级数据时候就一次性拿出了和二级有关联的三级数据,并合并进行查询,为了节省数据库查询次数)

  4. 此时我已经将所有数据和数据关系存储到缓存,此刻就可以遍历缓存中数据加载到界面中

  5. 实现点击行事件,点击子单据体行的时候显示对应孙单据体行,在点击行事件处获取对应点击行对应的第三级数据行,先保存孙单据体数据,然后清空孙单据体之前数据,将本次对应的第三级孙单据体数据显示在单据体中

  6. 每次在孙单据体中变动数据时候需要更新对应的缓存数据,保证数据一致性

  7. 在删除对应子单据体行数据时候同时删除对应孙单据体中所有数据

  8. 在提交单据的时候需要后台默认加载出所有第三级数据,然后保存,并情况缓存,这样才能利用框架顺利的存储到数据库中

  9. 在打开已经存在的单据时候需要实现同样的三级效果,会加载一次页面所有数据进入缓存,即可实现上述逻辑


技术点:

各类事件插件的实现、Redis缓存运用


这里代码基本上合并了,分为一个实现上述功能的类(MultilevelDataPlugIn.java)和一个操作Redis的类(TempCacheDataUtil.java)


业务类我就没有做拆分了,但是方法基本上拆得比较细了,用的过程中建议拆分几个工具类(组合关系方法、生成唯一标识符方法,界面赋值等)来使用,为了保护相关使用者的隐私做了一些加工,去掉了一些关键词,凑合看一下了


代码比较长,觉得有用的同学就快速滑到最后点个赞吧!~


MultilevelDataPlugIn.java

package kd.bos.bigdatatest;

import kd.bos.bigdatatest.vo.BigDataTestThreeManyAndTwoVO;
import kd.bos.bigdatatest.vo.BigDataTestThreeManyVO;
import kd.bos.bigdatatest.vo.BigDataTestThreeVO;
import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.entity.datamodel.events.ChangeData;
import kd.bos.entity.datamodel.events.PropertyChangedArgs;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.form.*;
import kd.bos.form.control.Control;
import kd.bos.form.control.EntryGrid;
import kd.bos.form.control.events.RowClickEvent;
import kd.bos.form.control.events.RowClickEventListener;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.form.events.BeforeDoOperationEventArgs;
import kd.bos.form.events.ClosedCallBackEvent;
import kd.bos.form.events.MessageBoxClosedEvent;
import kd.bos.form.operate.FormOperate;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.util.TempCacheDataUtil;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: 多级分录
 */
public class MultilevelDataPlugIn extends AbstractBillPlugIn implements RowClickEventListener {
    /**
     * 保存操作
     */
    private final static String KEY_SAVE = "save";
    /**
     * 第一级单据体
     */
    private final static String KEY_ONEENTITY = "kotn_oneentity";
    /**
     * 第二级子单据体
     */
    private final static String KEY_TWOENTITY = "kotn_twoentity";
    //
    /**
     * 第二级子单据体上选择添加二级数据按钮
     */
    private final static String KEY_ADD_TWO_DATA = "kotn_adddata";
    /**
     * 第三级孙单据体
     */
    private final static String KEY_THREEENTITY = "kotn_threeentity";
    /**
     * 第三级孙单据体上显示全部键
     */
    private final static String KEY_SHOWRES = "kotn_showres";
    /**
     * 日志
     */
    private static Log logger = LogFactory.getLog(AbstractBillPlugIn.class);
    /**
     * 删除第二级行数据回调事件标识
     */
    private final static String CALLBACKDELETECBS = "callbackdeletetwo";
    /**
     * 关键字-用于构建缓存key  单据编号 唯一
     **/
    private static final String BILLNO = "billno";
    /**
     * cacheRegion 缓存区域--尽量对应应用名称
     **/
    private static final String CACHE_REGION = "eccoCache";
    /**
     * oneToTwo 缓存区域--以二层数据为key存储所含三层数据number集合
     **/
    private static final String RELATION_TWO_TO_THREE = "twoToThreeQ";

    /**
     * oneToTwo 缓存区域--以一层数据为key存储所含二层数据number集合
     **/
    private static final String RELATION_ONE_TO_TWO = "oneToTwo";
    /**
     * 删除第三级孙单据体数据行
     **/
    private static final String KEY_DELETE_RES = "kotn_threedeleterow";

    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        // 侦听子单据体表格事件
        EntryGrid entryGridChild = this.getView().getControl(KEY_TWOENTITY);
        // 行点击
        entryGridChild.addRowClickListener(this);
    }


    /**
     * 操作前事件
     */
    @Override
    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
        super.beforeDoOperation(args);
        FormOperate operate = (FormOperate) args.getSource();
        String operateKey = operate.getOperateKey();
        //获取当前单据id
        String billId = this.getModel().getValue(BILLNO).toString();
        //匹配为删除资源行数据时
        if (KEY_DELETE_RES.equals(operateKey)) {
            int currentRow = this.getModel().getEntryCurrentRowIndex(KEY_THREEENTITY);
            DynamicObject resEntry = this.getModel().getEntryRowEntity(KEY_THREEENTITY , currentRow);
            deleteResRow(resEntry,billId);
        }
        if (KEY_SAVE.equals(operateKey)) {
            showAllRes(billId);
        }
    }

    /**
     * 执行回调函数
     */
    @Override
    public void confirmCallBack(MessageBoxClosedEvent messageBoxClosedEvent) {
        super.confirmCallBack(messageBoxClosedEvent);
        String callbackid = messageBoxClosedEvent.getCallBackId();
        if (callbackid.equals(CALLBACKDELETECBS)) {
            if (messageBoxClosedEvent.getResult().equals(MessageBoxResult.Yes)) {
                //删除第二级子单据体数据对应数据包
                int currentRow = this.getModel().getEntryCurrentRowIndex(KEY_TWOENTITY);
                DynamicObject cbsEntry = this.getModel().getEntryRowEntity(KEY_TWOENTITY , currentRow);
                //获取当前单据id
                String billId = this.getModel().getValue(BILLNO).toString();
                deleteTWORow(cbsEntry,billId);
                //清空对应CBS的资源数据
                this.getModel().deleteEntryData(KEY_THREEENTITY);
            }
        }
    }

    /**
     * 操作后事件
     */
    @Override
    public void afterDoOperation(AfterDoOperationEventArgs args) {
        super.afterDoOperation(args);
        //显示所有第三级数据
        if (StringUtils.equals(KEY_SHOWRES, args.getOperateKey())) {
            OperationResult opResult = args.getOperationResult();
            if (opResult != null && opResult.isSuccess()) {
                //获取当前单据id
                String billId = this.getModel().getValue(BILLNO).toString();
                //显示所有资源列表
                this.showAllRes(billId);
            }
        }
        //保存操作后删除缓存
        if (StringUtils.equals(KEY_SAVE, args.getOperateKey())) {
            OperationResult opResult = args.getOperationResult();
            if (opResult != null && opResult.isSuccess()) {
                //获取当前单据id
                String billId = this.getModel().getValue(BILLNO).toString();
                TempCacheDataUtil.removeCacheByBillId(billId,CACHE_REGION);
            }
        }
    }

    /**
     * @Author  zb
     * @Description 值改变事件-监听KEY_THREEENTITY  第三级单据体
     * @Date 16:40 2022/3/1
     * @Param [e]
     * @return void
    **/
    @Override
    public void propertyChanged(PropertyChangedArgs e) {
        //匹配变更字段
        if (StringUtils.equals("kotn_threeName", e.getProperty().getName())
                || StringUtils.equals("kotn_threeNumber", e.getProperty().getName())){
            ChangeData[] valueSet = e.getChangeSet();
            //合约规划包聚焦行
            int rowIndex = valueSet[0].getRowIndex();
            //获取当前单据id
            String billId = this.getModel().getValue(BILLNO).toString();
            //获取当前单据体对象
            DynamicObject dynamicObject = this.getModel().getEntryRowEntity(KEY_THREEENTITY, rowIndex);
            //获取本次修改数据的所属数据包所有数据
            BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY,
                    dynamicObject.getString("kotn_datapackageid"), billId, BigDataTestThreeManyAndTwoVO.class);

            //定义数据包Id
            String dataPackageId = bigDataTestThreeManyAndTwoVO.getDataPackageId();
            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOListOld = bigDataTestThreeManyAndTwoVO.getBigDataTestThreeManyVOList();
            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOListNew = new ArrayList<>();

            //遍历数据对象的值
            for (BigDataTestThreeManyVO bigDataTestThreeManyVO : bigDataTestThreeManyVOListOld){
                //匹配更改的数据行数据Id
                if(bigDataTestThreeManyVO.getRowId().equals(dynamicObject.getString("kotn_reshelpid"))){
                    //将新数据内容赋值给当前遍历对象
                    bigDataTestThreeManyVO = setBigDataTestThreeManyVO(dynamicObject);
                }
                //将遍历对象存储到List中
                bigDataTestThreeManyVOListNew.add(bigDataTestThreeManyVO);
            }

            //组装数据集
            //数据唯一标识符
            bigDataTestThreeManyAndTwoVO.setDataPackageId(dataPackageId);
            bigDataTestThreeManyAndTwoVO.setBigDataTestThreeManyVOList(bigDataTestThreeManyVOListNew);

            //将更新的数据存入缓存
            TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeManyAndTwoVO.getDataPackageId(), bigDataTestThreeManyAndTwoVO, billId);
        }
    }


    /**
     * 关闭回调函数
     */
    @Override
    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
        super.closedCallBack(closedCallBackEvent);
        List<DynamicObject> returnData = (List<DynamicObject>) closedCallBackEvent.getReturnData();
        if (StringUtils.equals(closedCallBackEvent.getActionId(), KEY_ADD_TWO_DATA)) {
            TwoDataSelectCallBack(returnData);
        }
    }

    /**
     * 将选择的第二级数据及其第三级数据清单回填
     */
    protected void TwoDataSelectCallBack(List<DynamicObject> returnTwoData) {

        //获取当前单据id
        String billId = this.getModel().getValue(BILLNO).toString();
        //判断数据集是否存在

        if (returnTwoData == null || returnTwoData.isEmpty()) {
            return ;
        }
        //获取父单据体的行id
        int rowIndexNow = this.getModel().getEntryCurrentRowIndex(KEY_ONEENTITY);
        //获取父单据体编号字段
        String costformentityId = this.getModel().getEntryRowEntity(KEY_ONEENTITY, rowIndexNow).getString("kotn_ctknumber");
        // 收集对应子单据体分录的id
        List<Long> twoIds = new ArrayList();
        //创建第一层与第二层记录关系map,第一层为key
        Map oneToTwoMap = new HashMap<String, Map<String, String>>();
        //遍历获取需要查询的子单据体分录id
        for (int i = 0; i < returnTwoData.size(); i++) {
            //子单据体分录的行id
            String twoEntityId = returnTwoData.get(i).get("twoEntityId").toString();
            twoIds.add(Long.valueOf(twoEntityId));
            //组装第一层与第二层的关系
            Map oneToTwoMapChild = recordParentToSon((Map<String, String>) oneToTwoMap.get(costformentityId), costformentityId, twoEntityId);
            oneToTwoMap.put(costformentityId, oneToTwoMapChild);
        }
        //存储关联关系到缓存中
        TempCacheDataUtil.saveMapToListCache(CACHE_REGION, RELATION_ONE_TO_TWO, oneToTwoMap, billId);

        //一次性查询出本次所有子单据体中的对应孙单据体分录数据汇总----第三级中对应包含第二级的外键标识符
        QFilter qFilter = new QFilter("treeentryentity.twoentryentity.id", QFilter.in, twoIds);
        //查询字段按需求设置,一般要把唯一标识符查询出来
        DynamicObjectCollection resinfos = QueryServiceHelper.query("kotn_threeData", "treeentryentity.id, " +
                "treeentryentity.twoentryentity.id," +
                " treeentryentity.subentryentity.threeName," +
                "treeentryentity.subentryentity.othertitle", new QFilter[]{qFilter});

        //创建第二层与第三层记录关系map,第一层为key
        Map twoToThreeMap = new HashMap<String, Map<String, String>>();
        for (int i = 0; i < resinfos.size(); i++) {
            if (null != resinfos.get(i).getString("treeentryentity.twoentryentity.id") && !"0".equals(resinfos.get(i).getString("treeentryentity.twoentryentity.id"))) {
                //得到遍历对象
                DynamicObject dynamicObjectThree = resinfos.get(i);

                //创建第三层数据简要对象模型
                BigDataTestThreeVO bigDataTestThreeVO = new BigDataTestThreeVO();
                bigDataTestThreeVO.setThreeNumber(resinfos.get(i).getString("treeentryentity.id"));
                bigDataTestThreeVO.setTwoNumber(resinfos.get(i).getString("treeentryentity.twoentryentity.id"));
                bigDataTestThreeVO.setThreeName(resinfos.get(i).getString("treeentryentity.twoentryentity.threeName"));
                bigDataTestThreeVO.setOthertitle(resinfos.get(i).getString("treeentryentity.twoentryentity.othertitle"));

                //遍历存储数据到缓存
                TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeVO.getTwoNumber(), bigDataTestThreeVO, billId);

                //遍历记录第二层与第三层关联关系map
                Map twoToThreeMapChild = recordParentToSon((Map<String, String>) twoToThreeMap.get(bigDataTestThreeVO.getTwoNumber()), bigDataTestThreeVO.getTwoNumber(), bigDataTestThreeVO.getThreeNumber());
                twoToThreeMap.put(bigDataTestThreeVO.getTwoNumber(), twoToThreeMapChild);
            }
        }
        //存储关联关系到缓存中
        TempCacheDataUtil.saveMapToListCache(CACHE_REGION, RELATION_TWO_TO_THREE, twoToThreeMap, billId);


        /********************************** 给界面赋值 ********************************/

        int[] rows = this.getModel().batchCreateNewEntryRow(KEY_TWOENTITY, returnTwoData.size());
        //rows长度
        int rowsLength = rows.length;
        Date date = new Date();
        //设置时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取String类型的时间
        String createdate = sdf.format(date);
        createdate = createdate.replaceAll("[[\\s-:punct:]]", "");
        //合约规划包编号
        int rowIndex = this.getModel().getEntryCurrentRowIndex(KEY_ONEENTITY);
        DynamicObject ctkentry = this.getModel().getEntryRowEntity(KEY_ONEENTITY, rowIndex);
        //第一级单据体单内数据
        DynamicObjectCollection entrys = this.getModel().getEntryEntity(KEY_ONEENTITY);
        //entrys长度
        int entrysLength = entrys.size();

        //收集第二级子单据体所有数据
        List<Map<String, Object>> twoMap = new ArrayList<Map<String, Object>>();
        for (int z = 0; z < entrysLength; z++) {
            //只收集第二级数据为不作废状态的内容
            if (entrys.get(z).getBoolean("kotn_isinvalid") == false) {
                DynamicObjectCollection subentrys = this.getModel().getEntryRowEntity(KEY_ONEENTITY, z).getDynamicObjectCollection(KEY_TWOENTITY);
                for (DynamicObject subentry : subentrys) {
                    Map<String, Object> entry = new HashMap<String, Object>();
                    entry.put("unitproject", subentry.get("kotn_cbsunitprojects"));
                    entry.put("cbs", subentry.get("kotn_cbs"));
                    entry.put("amount", subentry.getBigDecimal("kotn_amountfield"));
                    twoMap.add(entry);
                }
            }
        }
        //数据包Id List
        List dataPackageIdList = new ArrayList<>();

        //查询已经存在所有数据包
        String key = "dataPackageIdAll";
        Map<String, List> dataPackageIdMap = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY, key, billId,Map.class);
        //如果已经存在则赋值
        if(null != dataPackageIdMap && null != dataPackageIdMap.get(key)){
            //将查询到的Map中List数据赋值给数据包Id List
            dataPackageIdList = dataPackageIdMap.get(key);
        }else{
            dataPackageIdMap = new HashMap<>();
        }

        // 遍历填充子单据体分录数据
        for (int i = 0; i < rowsLength; i++) {

            //识别id:分录id+创建时间点
            String treeentityid = returnTwoData.get(i).get("id").toString() + createdate;
            //数据包ID---用于标识数据集合对应字段据体行---下方for第三层用到
            String dataPackageId = createResDataPackageId(costformentityId, treeentityid);
            //唯一标识符
            this.getModel().setValue("kotn_subhelpid", dataPackageId, rows[i]);
            //字段1
            this.getModel().setValue("kotn_cbs", returnTwoData.get(i).get("kotn_cbsid"), rows[i]);
            //字段2
            this.getModel().setValue("kotn_initamount", returnTwoData.get(i).get("kotn_amount"), rows[i]);
            //字段3
            this.getModel().setValue("kotn_cbsunitprojects", returnTwoData.get(i).get("kotn_unitpros"), rows[i]);

            //遍历获取第三层数据
            //找寻第二层对应的第三层数据,并写入对象缓存

            //创建第三级数据
            IDataModel modelRes = this.getModel();
            Collection<DynamicObject> colRes = new LinkedList<>();
            DynamicObject objRes;
            DynamicObjectCollection entryRes = modelRes.getDataEntity(true).getDynamicObjectCollection(KEY_THREEENTITY);
            DynamicObjectType dynamicObjectResType = entryRes.getDynamicObjectType();


            //获取该行对应的下级单据体数据关系(第二级对第三级的关系)
            List twoToThreeMapList = TempCacheDataUtil.getMapsCache(CACHE_REGION, RELATION_TWO_TO_THREE, returnTwoData.get(i).get("twoEntityId").toString(), billId);
            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOList = new ArrayList();

            if (twoToThreeMapList != null) {
                for (int k = 0; k < twoToThreeMapList.size(); k++) {
                    //通过第二层查询第三层所需数据
                    BigDataTestThreeVO bigDataTestThreeVO = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY, (String) twoToThreeMapList.get(k), billId, BigDataTestThreeVO.class);

                    //构建显示数据
                    BigDataTestThreeManyVO bigDataTestThreeManyVO = new BigDataTestThreeManyVO();

                    bigDataTestThreeManyVO.setThreeNumber(bigDataTestThreeVO.getThreeNumber());
                    bigDataTestThreeManyVO.setTwoNumber(bigDataTestThreeVO.getTwoNumber());
                    bigDataTestThreeManyVO.setThreeName(bigDataTestThreeVO.getThreeName());
                    bigDataTestThreeManyVO.setOthertitle(bigDataTestThreeVO.getOthertitle());
                    //存入行特征值
                    bigDataTestThreeManyVO.setRowId(createResRowId(dataPackageId, bigDataTestThreeVO.getThreeNumber()));
                    bigDataTestThreeManyVO.setParentRowId(dataPackageId);
                    //添加到对应List
                    bigDataTestThreeManyVOList.add(bigDataTestThreeManyVO);

                    //-------------------写入界面对应字段----------------------
                    objRes = (DynamicObject) dynamicObjectResType.createInstance();
                    //数据包ID
                    objRes.set("kotn_datapackageid", dataPackageId);
                    //识别id:分录id+创建时间点
                    objRes.set("kotn_reshelpid", bigDataTestThreeManyVO.getRowId());
                    //编号
                    objRes.set("kotn_resctknumber", bigDataTestThreeManyVO.getThreeNumber());
                    //名称
                    objRes.set("kotn_resctkname", bigDataTestThreeManyVO.getThreeName());
                    //单位工程
                    colRes.add(objRes);
                }
                entryRes.addAll(colRes);
                this.getView().updateView(KEY_THREEENTITY);

                //组装数据集
                BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = new BigDataTestThreeManyAndTwoVO();
                //数据唯一标识符
                bigDataTestThreeManyAndTwoVO.setDataPackageId(dataPackageId);
                bigDataTestThreeManyAndTwoVO.setBigDataTestThreeManyVOList(bigDataTestThreeManyVOList);
                dataPackageIdList.add(dataPackageId);
                //存入缓存
                TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeManyAndTwoVO.getDataPackageId(), bigDataTestThreeManyAndTwoVO, billId);
            }
        }
        //重新组装Map数据
        dataPackageIdMap.put(key, dataPackageIdList);
        //存入缓存
        TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, key, dataPackageIdMap, billId);
    }

    /**
     * @Author  zb
     * @Description 分录行点击事件
     * @Date 13:52 2021/12/23
     * @Param [evt]
     * @return void
    **/
    @Override
    public void entryRowClick(RowClickEvent evt) {
        // 单据体焦点行、焦点单元格切换时,触发此事件:
        // 1. 通过点击鼠标,切换行、单元格时,触发事件;
        // 2. 按键盘上下左右键切换单元格,不触发事件,但是开始编辑单元格值,触发事件
        // 插件可以在此事件,第一时间获取表格焦点行的变化,据此刷新界面控件状态;

        Control source = (Control) evt.getSource();
        //获取X单据体key
        String entryKey = source.getKey();
        if (StringUtils.equals(KEY_TWOENTITY, entryKey)) {

            int rowNum = evt.getRow();
            //非取消点击行
            if (rowNum >= 0) {
                //获取当前单据id
                String billId = this.getModel().getValue(BILLNO).toString();

                //更新改变点击前的数据到缓存
                DynamicObjectCollection dynamicObjectCollectionResOld = this.getModel().getDataEntity().getDynamicObjectCollection(KEY_THREEENTITY);

                //存在即赋值
                if (dynamicObjectCollectionResOld.size() > 0) {
                    //分类组装数据包
                    Map<String,BigDataTestThreeManyAndTwoVO> bigDataTestThreeManyAndTwoByPackageIdMap = recordParentToSonBigDataTestThreeManyAndTwoMap(dynamicObjectCollectionResOld);
                    //遍历点击前资源数据
                    for(Map.Entry<String, BigDataTestThreeManyAndTwoVO> entryMap : bigDataTestThreeManyAndTwoByPackageIdMap.entrySet()) {
                        //遍历获取Map中BigDataTestThreeManyAndTwoVO对象值
                        BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = entryMap.getValue();
                        //存入缓存
                        TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeManyAndTwoVO.getDataPackageId(), bigDataTestThreeManyAndTwoVO, billId);
                    }
                }

                //清空点击前数据
                this.getModel().deleteEntryData(KEY_THREEENTITY);

                EntryGrid grid = this.getView().getControl(KEY_TWOENTITY);
                int[] selectrows = grid.getSelectRows();
                //遍历所有勾选的行
                for (int rowNumber : selectrows) {
                    //获取当前子单据体对象
                    DynamicObject dynamicObject = this.getModel().getEntryRowEntity(KEY_TWOENTITY, rowNumber);
                    //获取本次点击的数据
                    BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY,
                            dynamicObject.getString("kotn_subhelpid"), billId, BigDataTestThreeManyAndTwoVO.class);

                    if (null != bigDataTestThreeManyAndTwoVO && null != bigDataTestThreeManyAndTwoVO.getDataPackageId()) {
                        //遍历在界面显示
                        showResByBigDataTestThreeManyAndTwoVO(bigDataTestThreeManyAndTwoVO);
                    }
                }
            }
            //刷新界面显示
            this.getView().updateView(KEY_THREEENTITY);
        }
    }



    /**
     * @Author  zb
     * @Description 显示所有第三级数据
     * @Date 17:03 2021/12/13
     * @Param [billId]
     * @return void
    **/
    public void showAllRes(String billId) {

        //从缓存中获取数据包IdList
        String key = "dataPackageIdAll";
        Map<String, List> dataPackageIdMap = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY, key, billId,Map.class);
        List dataPackageIdList = dataPackageIdMap.get(key);
        //清空界面显示
        logger.info("开始清空界面显示");
        this.getModel().deleteEntryData(KEY_THREEENTITY);
        //遍历获取对应数据包Id数据
        for(int i = 0;i < dataPackageIdList.size();i++){

            //从缓存中获取对应的数据包数据
            BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY,
                    dataPackageIdList.get(i).toString(), billId, BigDataTestThreeManyAndTwoVO.class);

            if (null != bigDataTestThreeManyAndTwoVO && null != bigDataTestThreeManyAndTwoVO.getDataPackageId()) {

                //显示资源数据
                logger.info("显示资源数据");
                showResByBigDataTestThreeManyAndTwoVO(bigDataTestThreeManyAndTwoVO);
                //刷新界面显示
                this.getView().updateView(KEY_THREEENTITY);
                logger.info("刷新界面显示");
            } else {
                //如果为空则要新增分录为空列表--此处一般不为空
                //需要保存
            }
        }
    }


    /**
     * @Author  zb
     * @Description 载入单据
     * @Date 13:54 2021/12/24
     * @Param [e]
     * @return void
    **/
    @Override
    public void afterBindData(EventObject e) {
        super.afterBindData(e);
        //获取当前单据id
        String billId = this.getModel().getValue(BILLNO).toString();
        //第一层单据体数据集合
        DynamicObjectCollection oneDynamicObjectCollection = this.getModel().getEntryEntity(KEY_ONEENTITY);
        //数据包Id List
        List dataPackageIdList = new ArrayList<>();
        //遍历第一层数据
        for(DynamicObject oneDynamicObject : oneDynamicObjectCollection){
            //获取当前行子单据体对象
            // 从单据体行数据包中,取子单据体行集合
            DynamicObjectCollection twoDynamicObjectCollection = oneDynamicObject.getDynamicObjectCollection(KEY_TWOENTITY);
            //获取当前合约规划包编号
            String costformentityId = oneDynamicObject.getString("kotn_ctknumber");
            //创建第一层与第二层记录关系map,第一层为key
            Map oneToTwoMap = new HashMap<String, Map<String, String>>();
            //遍历获取需要查询的CBSId
            for (DynamicObject twoDynamicObject : twoDynamicObjectCollection) {
                //目标成本编制的行Id
                String subentryentityId = twoDynamicObject.get("kotn_subhelpid").toString();
                //组装第一层与第二层的关系
                Map oneToTwoMapChild = recordParentToSon((Map<String, String>) oneToTwoMap.get(costformentityId), costformentityId, subentryentityId);
                oneToTwoMap.put(costformentityId, oneToTwoMapChild);
                dataPackageIdList.add(twoDynamicObject.getString("kotn_subhelpid"));
            }
            //一级与二级关系存储关联关系到缓存中
            TempCacheDataUtil.saveMapToListCache(CACHE_REGION, RELATION_ONE_TO_TWO, oneToTwoMap, billId);
        }
        //重新组装所有Map数据
        String key = "dataPackageIdAll";
        Map<String, List> dataPackageIdMap = new HashMap<>();
        dataPackageIdMap.put(key, dataPackageIdList);
        //dataPackageIdAll存入缓存
        TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, key, dataPackageIdMap, billId);
        //创建第二层与第三层记录关系map,第一层为key
        Map twoToThreeMap = new HashMap<String, Map<String, String>>();
        //第三层单据体数据集合
        DynamicObjectCollection threeDynamicObjectCollection = this.getModel().getEntryEntity(KEY_THREEENTITY);
        //分类组装数据包
        Map<String,BigDataTestThreeManyAndTwoVO> bigDataTestThreeManyAndTwoByPackageIdMap = recordParentToSonBigDataTestThreeManyAndTwoMap(threeDynamicObjectCollection);

        for(Map.Entry<String, BigDataTestThreeManyAndTwoVO> entryMap : bigDataTestThreeManyAndTwoByPackageIdMap.entrySet()) {
            //遍历获取Map中BigDataTestThreeManyAndTwoVO对象值
            BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = entryMap.getValue();
            //存入缓存
            TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeManyAndTwoVO.getDataPackageId(), bigDataTestThreeManyAndTwoVO, billId);
        }

    }

    /**
     * @Author  zb
     * @Description 删除第三级孙单据体行数据缓存
     * @Date 10:34 2021/12/24
     * @Param [resDynamicObject]
     * @return void
    **/
    public void deleteResRow(DynamicObject resDynamicObject, String billId){

        //传入关键数据不为空
        if(resDynamicObject != null && null != resDynamicObject.get("kotn_datapackageid") && null != resDynamicObject.get("kotn_reshelpid")){
            //从缓存中获取对应的数据包数据
            BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY,
                    (String) resDynamicObject.get("kotn_datapackageid"), billId, BigDataTestThreeManyAndTwoVO.class);
            //获取原缓存中数据
            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOList = bigDataTestThreeManyAndTwoVO.getBigDataTestThreeManyVOList();
            //创建新的数据(遍历删除后)
            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOListNew = new ArrayList<>();
            //遍历删除对应行数据
            for (BigDataTestThreeManyVO bigDataTestThreeManyVO : bigDataTestThreeManyVOList){
                //不是本次删除的数据继续添加到新的List
                if(!resDynamicObject.getString("kotn_reshelpid").equals(bigDataTestThreeManyVO.getRowId())){
                    bigDataTestThreeManyVOListNew.add(bigDataTestThreeManyVO);
                }
            }
            bigDataTestThreeManyAndTwoVO.setBigDataTestThreeManyVOList(bigDataTestThreeManyVOListNew);
            //更新存入缓存
            TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, bigDataTestThreeManyAndTwoVO.getDataPackageId(), bigDataTestThreeManyAndTwoVO, billId);

        }

    }

    /**
     * @Author  zb
     * @Description 删除第二级行数据时执行,删除存储在缓存中的数据包Id
     * @Date 14:53 2021/12/27
     * @Param [cbsDynamicObject, billId]
     * @return void
    **/
    public void deleteTWORow(DynamicObject cbsDynamicObject, String billId){

        //传入关键数据不为空
        if(cbsDynamicObject != null && null != cbsDynamicObject.get("kotn_subhelpid")){
            //清理所有资源Map中数据
            //从缓存中获取数据包IdList
            String key = "dataPackageIdAll";
            Map<String, List> dataPackageIdMap = TempCacheDataUtil.getObjectByCache(CACHE_REGION, KEY_THREEENTITY, key, billId,Map.class);
            //获取已存数据包list
            List dataPackageIdList = dataPackageIdMap.get(key);
            //数据包Id 新List
            List dataPackageIdListNew = new ArrayList<>();
            //遍历删除对应行数据
            for (int i = 0;i < dataPackageIdList.size();i++){
                String dataPackageId = (String) dataPackageIdList.get(i);
                //不是本次删除的数据继续添加到新的List
                if(!cbsDynamicObject.get("kotn_subhelpid").equals(dataPackageId)){
                    dataPackageIdListNew.add(dataPackageId);
                }
            }
            dataPackageIdMap.put(key,dataPackageIdListNew);
            //存入缓存
            TempCacheDataUtil.saveObjectCache(CACHE_REGION, KEY_THREEENTITY, key, dataPackageIdMap, billId);
        }
    }

    /**
     * @Author  zb
     * @Description 组装一对多父子关系
     * @Date 14:28 2021/12/13
     * @Param [sourceMap, key, value]
     * @return java.util.Map
    **/
    public Map recordParentToSon(Map sourceMap, String key, String value) {
        //记录第该层与上一层数据关系
        //如果Map中已经存在
        if (null != sourceMap && null != sourceMap.get(key)) {
            //获取已经存储的关联List数据
            List sonValueList = (List) sourceMap.get(key);
            //添加到现有List中去
            sonValueList.add(value);
            //更新map
            sourceMap.put(key, sonValueList);
        } else {
            //如果还不存在该关联关系的map
            List sonNumbersList = new ArrayList();
            //将二层数据number存入List
            sonNumbersList.add(value);
            //创建并存储map
            Map map = new HashMap<String, List>();
            map.put(key, sonNumbersList);
            sourceMap = map;
        }
        return sourceMap;
    }

    /**
     * @Author  zb
     * @Description 组装Map
     * @Date 16:08 2021/12/13
     * @Param [sourceMap, key, value]
     * @return java.util.Map
    **/
    public Map recordParentToSonBigDataTestThreeManyAndTwoMap(DynamicObjectCollection dynamicObjectCollectionResOld) {
        Map<String,BigDataTestThreeManyAndTwoVO> bigDataTestThreeManyAndTwoByPackageIdMap = new HashMap<>();
        for (DynamicObject dynamicObjectResOld : dynamicObjectCollectionResOld) {
            String dataPackageId = dynamicObjectResOld.getString("kotn_datapackageid");
            //封装界面数据到bigDataTestThreeManyVO对象
            BigDataTestThreeManyVO bigDataTestThreeManyVO = setBigDataTestThreeManyVO(dynamicObjectResOld);
            //如果对应数据包Map已经存在
            if(null != bigDataTestThreeManyAndTwoByPackageIdMap && null != bigDataTestThreeManyAndTwoByPackageIdMap.get(dataPackageId)){
                //查询map中对应数据包对象
                BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = bigDataTestThreeManyAndTwoByPackageIdMap.get(dataPackageId);
                //查询对象中已经存在的List
                List<BigDataTestThreeManyVO> bigDataTestThreeManyVOList = bigDataTestThreeManyAndTwoVO.getBigDataTestThreeManyVOList();
                //将本次遍历的数据添加到已经存在的List中
                bigDataTestThreeManyVOList.add(bigDataTestThreeManyVO);
                //重新组装数据
                bigDataTestThreeManyAndTwoVO.setBigDataTestThreeManyVOList(bigDataTestThreeManyVOList);
                //覆盖map,更新数据
                bigDataTestThreeManyAndTwoByPackageIdMap.put(dataPackageId,bigDataTestThreeManyAndTwoVO);
            }else{
                //不存在该数据包的map
                //创建新存储对象
                BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO = new BigDataTestThreeManyAndTwoVO();
                //创建所需List
                List<BigDataTestThreeManyVO> bigDataTestThreeManyVOList = new ArrayList<>();
                //讲当前遍历对象存入
                bigDataTestThreeManyVOList.add(bigDataTestThreeManyVO);

                //添加对象数据
                bigDataTestThreeManyAndTwoVO.setDataPackageId(dataPackageId);
                bigDataTestThreeManyAndTwoVO.setBigDataTestThreeManyVOList(bigDataTestThreeManyVOList);

                //生成map,添加数据
                bigDataTestThreeManyAndTwoByPackageIdMap.put(dataPackageId,bigDataTestThreeManyAndTwoVO);
            }
        }
        return bigDataTestThreeManyAndTwoByPackageIdMap;
    }


    /**
     * @Author  zb
     * @Description 根据界面DynamicObject生成BigDataTestThreeManyVO对象数据
     * @Date 16:24 2022/3/3
     * @Param [dynamicObjectResOld]
     * @return kd.zmzy.contplanbill.vo.BigDataTestThreeManyVO
    **/
    public BigDataTestThreeManyVO setBigDataTestThreeManyVO(DynamicObject dynamicObjectResOld){
        //获取老显示数据
        BigDataTestThreeManyVO bigDataTestThreeManyVO = new BigDataTestThreeManyVO();
        //开始给数据对象封装
        //判断资源ID是否存在
        if (null != dynamicObjectResOld.getString("kotn_threenumber")) {
            bigDataTestThreeManyVO.setThreeNumber(((DynamicObject) dynamicObjectResOld.get("kotn_threenumber")).getString("id"));
        }
        bigDataTestThreeManyVO.setTwoNumber(dynamicObjectResOld.getString("kotn_twonumber"));
        bigDataTestThreeManyVO.setThreeName(dynamicObjectResOld.getString("kotn_threeName"));
        bigDataTestThreeManyVO.setOthertitle(dynamicObjectResOld.getString("kotn_othertitle"));

        //存入行特征值
        bigDataTestThreeManyVO.setRowId(dynamicObjectResOld.getString("kotn_reshelpid"));
        bigDataTestThreeManyVO.setParentRowId(dynamicObjectResOld.getString("kotn_datapackageid"));

        return bigDataTestThreeManyVO;
    }


    /**
     * @return java.lang.String
     * @Author zb
     * @Description 组装资源数据包Id
     * @Date 16:26 2021/12/9
     * @Param [costformentityId, treeentityid]
     **/
    private String createResDataPackageId(String costformentityId, String treeentityid) {
        String dataPackageId = costformentityId + "&" + treeentityid + "#";
        return dataPackageId;
    }

    /**
     * @return java.lang.String
     * @Author zb
     * @Description 生成行数据Id
     * @Date 16:43 2021/12/9
     * @Param [dataPackageId, entityID]
     **/
    private String createResRowId(String dataPackageId, String entityID) {
        String rowId = dataPackageId + entityID;
        return rowId;
    }

    /**
     * @Author  zb
     * @Description 对第三级孙单据体界面赋值
     * @Date 11:01 2021/12/13
     * @Param [bigDataTestThreeManyAndTwoVO]
     * @return void
    **/
    private void showResByBigDataTestThreeManyAndTwoVO(BigDataTestThreeManyAndTwoVO bigDataTestThreeManyAndTwoVO){

            List<BigDataTestThreeManyVO> bigDataTestThreeManyVOList = bigDataTestThreeManyAndTwoVO.getBigDataTestThreeManyVOList();
            //创建第三级数据
            IDataModel modelRes = this.getModel();
            Collection<DynamicObject> colRes = new LinkedList<>();
            DynamicObject objRes;
            DynamicObjectCollection entryRes = modelRes.getDataEntity(true).getDynamicObjectCollection(KEY_THREEENTITY);
            DynamicObjectType dynamicObjectResType = entryRes.getDynamicObjectType();
            for (BigDataTestThreeManyVO bigDataTestThreeManyVO : bigDataTestThreeManyVOList) {
                //写入界面对应字段----------------------
                objRes = (DynamicObject) dynamicObjectResType.createInstance();
                //数据包ID
                objRes.set("kotn_datapackageid", bigDataTestThreeManyAndTwoVO.getDataPackageId());
                //识别id:分录id+创建时间点
                objRes.set("kotn_reshelpid", bigDataTestThreeManyVO.getRowId());
                //合约规划包编号
                objRes.set("kotn_threenumber", bigDataTestThreeManyVO.getThreeNumber());
                //合约规划包名称
                objRes.set("kotn_twonumber", bigDataTestThreeManyVO.getTwoNumber());
                //单位工程
                //项目名称
                objRes.set("kotn_threeName", bigDataTestThreeManyVO.getThreeName());
                //项目特征
                objRes.set("kotn_othertitle", bigDataTestThreeManyVO.getOthertitle());

                colRes.add(objRes);
            }
            entryRes.addAll(colRes);
    }


}

TempCacheDataUtil.java

package kd.bos.util;

import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.dataentity.serialization.SerializationUtils;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.cache.AppCache;
import kd.bos.entity.cache.IAppCache;
import kd.bos.entity.datamodel.IDataModel;
import kd.bos.servicehelper.util.DynamicObjectSerializeUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName AutoSaveBillUtil
 * @Author zb
 * @Description TODO
 * @Date 2021/4/20 14:15
 **/
public class TempCacheDataUtil {

    /**
     * ID 关键字-用于构建缓存key
    **/
    private static final String ID = "id";






    /**
     * @Author  zb
     * @Description 存储实体批量缓存数据
     * @Date 21:24 2021/11/17
     * @Param [cacheRegion, entityName, dynamicObjectCollection]
     * @return void
    **/
    public static void saveDynamicObjectCollectionCache(String cacheRegion, String entityName, DynamicObjectCollection dynamicObjectCollection, String billId){

        Map map = new HashMap<String,List>();
        //遍历存储
        for(DynamicObject dynamicObject : dynamicObjectCollection){
            //以单个数据保存
            saveDynamicObjectCache(cacheRegion,entityName,dynamicObject,billId);
        }
    }

    /**
     * @Author  zb
     * @Description 存储实体缓存数据
     * @Date 21:24 2021/11/17
     * @Param [cacheRegion, entityName, dynamicObject]
     * @return void
    **/
    public static void saveDynamicObjectCache(String cacheRegion, String entityName, DynamicObject dynamicObject, String billId){

        //构建缓存key
        String cacheId = entityName+billId+dynamicObject.get("number");

        //当前表单数据类型
        DynamicObjectType objectType = dynamicObject.getDynamicObjectType();
        //序列化对象
        String objectSerialization = DynamicObjectSerializeUtil.serialize(new Object[]{dynamicObject},objectType);
        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //设置缓存内容
        appCache.put(cacheId,objectSerialization);
    }



    /**
     * @Author  zb
     * @Description 存储实体缓存数据
     * @Date 21:24 2021/11/17
     * @Param [cacheRegion, entityName, dynamicObject]
     * @return void
     **/
    public static void saveObjectCache(String cacheRegion, String entityName, String key, Object object,String billId){

        //构建缓存key
        String cacheId = entityName+billId+key;
        //序列化数据
        String json = SerializationUtils.toJsonString(object);
        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //设置缓存内容
        appCache.put(cacheId,json);
    }

    /**
     * @Author  zb
     * @Description 储存Map
     * @Date 0:36 2021/11/18
     * @Param [cacheRegion, relationName, map]
     * @return void
    **/
    public static void saveMapToListCache(String cacheRegion,String relationName,Map<String, Map<String,List>> map,String billId){
       
       for(Map.Entry<String, Map<String,List>> entryMap: map.entrySet()) {
          
          for (Map.Entry<String, List> entry: entryMap.getValue().entrySet()) {
                //获取key值
                String key = entry.getKey();
                //获取value中List值
                List list = entry.getValue();
                //构建缓存key
                String cacheId = relationName+billId+key;
                //缓存
                IAppCache appCache = AppCache.get(cacheRegion);
                //设置缓存内容
                appCache.put(cacheId,list);
            }
       }
       
       
       
       
        
    }

    public static List getMapsCache(String cacheRegion,String relationName,String number,String billId){

        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //获取缓存数据
        List mapListCache = appCache.get(relationName+billId+number,List.class);

        return mapListCache;
    }



    /**
     * @Author  zb
     * @Description 获取缓存中表单对象
     * @Date 17:49 2021/11/17
     * @Param [iDataModel]
     * @return void
    **/
    public static DynamicObject getDynamicObjectByCache(IDataModel iDataModel, String cacheRegion, String entityName, String number){

        //当前表单数据类型
        DynamicObjectType objectType = EntityMetadataCache.getDataEntityType(entityName);
        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
//        DynamicObject dynamicObject = appCache.get(entityName+number,DynamicObject.class);
        //缓存中序列化数据
        String cacheString = appCache.get(entityName+number,String.class);
        if(!StringUtils.isEmpty(cacheString)){
            //反序列化
            Object[] toObject = DynamicObjectSerializeUtil.deserialize(cacheString,objectType);
            //对于单个对象数据直接获取设值
            DynamicObject toDyObject = (DynamicObject) toObject[0];
            return toDyObject;
        }
        return null;

    }


    /**
     * @Author  zb
     * @Description 获取缓存对象
     * @Date 11:17 2021/11/18
     * @Param [cacheRegion, entityName, key, clazz]
     * @return java.lang.Object
    **/
    public static <T> T getObjectByCache(String cacheRegion, String entityName, String key,String billId, Class<T> clazz){

        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //缓存中序列化数据
        String cacheString = appCache.get(entityName+billId+key,String.class);
        if(!StringUtils.isEmpty(cacheString)){
            //反序列化
            T t = SerializationUtils.fromJsonString(cacheString,clazz);
            //对于单个对象数据直接获取设值
            return t;
        }
        return null;

    }



    /**
     * @Author  zb
     * @Description 清理缓存
     * @Date 16:23 2021/11/17
     * @Param [number, cacheRegion]
     * @return java.lang.String
    **/
    public static String removeCache(String cacheId,String cacheRegion){
        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //清空缓存
        appCache.remove(cacheId);

        return cacheId;
    }


    /**
     * @Author  zb
     * @Description 清理缓存
     * @Date 16:23 2021/11/17
     * @Param [number, cacheRegion]
     * @return java.lang.String
     **/
    public static void removeCacheByBillId(String billId,String cacheRegion){
        //缓存
        IAppCache appCache = AppCache.get(cacheRegion);
        //清空缓存
        appCache.remove("*"+billId+"*");
    }



}





赞 12