JRT多维取数据三件套

news2024/9/23 1:27:56

今天补齐DolerData判断数据是否存在的API,即M的$d。

兜兜转转,经过近十年探索,3年的酝酿,10个月的开发,JRT终于集齐多维取数据三件套。分别是$get,$listget,$data。通过多维取数据的支持,JRT特别适合医疗数据表关系参照多的运用场景,使开发者开发业务爬行主数据周边几十上百个相关表不在受限数据库交互性能。也使开发脱离原始SQL,不用绞尽脑汁的join一堆相关表来优化性能。在整个业务代码无缝支持多数据库情况下,比同等spring+mybats体系的程序性能高几倍到几十倍。

对应的JRT的API就是下面5个

	/**
     * 通过主键查询数据,带缓存的查询,用来解决关系库的复杂关系数据获取,顶替Cache的$g
     *
     * @param modelClass 实体类型
     * @param id         主键
     * @param <T>        泛型
     * @return 一行数据
     * @throws Exception
     */
    public <T> T DolerGet(Class modelClass, Object id) throws Exception;

    /**
     * 通过多列值唯一得到数据,带缓存的查询,用来解决关系库的复杂关系数据索引唯一获取
     *
     * @param modelClass 实体类型
     * @param para         索引参数
     * @param <T>        泛型
     * @return 一行数据
     * @throws Exception
     */
    public <T> T DolerGet(Class modelClass, HashParam para) throws Exception ;

    /**
     * 通过多列值判断数据是否存在,带缓存的判断,用来解决关系库的复杂关系数据的存在判断,登记$d
     *
     * @param modelClass 实体类型
     * @param para         索引参数
     * @return 一行数据
     * @throws Exception
     */
    public boolean DolerData(Class modelClass, HashParam para) throws Exception ;


    /**
     * 通过主键查询一列数据
     *
     * @param modelClass 实体类型
     * @param id 主键
     * @param colName 列名
     * @return 一行具体列数据
     * @throws Exception
     */
    public Object DolerGetCol(Class modelClass, Object id,String colName) throws Exception;

    /**
     * 通过主键查询一行数据的CName
     *
     * @param modelClass 实体类型
     * @param id 主键
     * @return 一行具体列数据
     * @throws Exception
     */
    public String DolerGetCName(Class modelClass, Object id) throws Exception;

用DolerData代替CheckHas的性能差距
在这里插入图片描述
综合带有取一个周边数据和判断子数据存在,还有取单列数据的性能差距
在这里插入图片描述
通过多列取唯一行的性能差距
在这里插入图片描述

测试代码

import JRT.Core.Util.RuleNumberUtil;
import JRT.DAL.ORM.Global.GlobalManager;
import JRTBLLBase.BaseHttpHandlerNoSession;
import JRTBLLBase.Helper;
import JRT.Core.Dto.HashParam;
import JRT.Core.Dto.ParamDto;
import JRT.Core.Dto.OutParam;
import JRT.Model.Entity.*;
import JRT.Core.Util.Convert;
import JRT.Core.MultiPlatform.JRTContext;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 测试DolerGet和不用DolerGet的性能差别以及在哈希表放千万行数据的内存占用
 *
 */
public class ashDolerGetTest extends BaseHttpHandlerNoSession {

    /**
     * 用Doler系列测试,综合性能
     * @return
     */
    public String DolerMethodsTest() throws Exception
    {
        String ret="";
        //用DolerData判断
        long start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        //取一个标本测试取周边数据
        List<RPVisitNumber> visList = EntityManager().FindAllSimple(RPVisitNumber.class, null,"",1,null,null);
        //刚清库标本数据不够,多循环几次代表多标本
        for(int i=0;i<50;i++) {
            if (visList != null && visList.size() > 0) {
                for (RPVisitNumber vis : visList) {
                    //平均每个标本取20次周边数据
                    for(int j=0;j<20;j++) {
                        if (vis.LocationDR != null) {
                            BTLocation loc = EntityManager().DolerGet(BTLocation.class, vis.LocationDR);
                        }
                        String hosName = EntityManager().DolerGetCName(BTHospital.class, vis.HospitalDR);
                        HashParam hs = new HashParam();
                        hs.Add("VisitNumberDR", vis.RowID);
                        if (EntityManager().DolerData(RPVisitNumberReport.class, hs)) {
                            //System.out.println("存在报告");
                        }
                    }
                }
            }
        }
        long end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret="用DolerGet通过索引取数据耗时:"+(end-start);



        //不用DolerData判断
        start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        visList = EntityManager().FindAllSimple(RPVisitNumber.class, null);
        //刚清库标本数据不够,多循环几次代表多标本
        for(int i=0;i<50;i++) {
            if (visList != null && visList.size() > 0) {
                for (RPVisitNumber vis : visList) {
                    //平均每个标本取20次周边数据
                    for(int j=0;j<20;j++) {
                        if (vis.LocationDR != null) {
                            BTLocation loc = EntityManager().GetById(BTLocation.class, vis.LocationDR);
                        }
                        BTHospital hos = EntityManager().GetById(BTHospital.class, vis.HospitalDR);
                        String hosName = hos.CName;
                        HashParam hs = new HashParam();
                        hs.Add("VisitNumberDR", vis.RowID);
                        if (EntityManager().CheckHasData(RPVisitNumberReport.class, hs, null, null)) {
                            //System.out.println("存在报告");
                        }
                    }
                }
            }
        }
        end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret+=",直接查数据库取数据耗时:"+(end-start);
        return ret;
    }

    /**
     * 用DolerData判断数据是否存在
     * @return
     */
    public String DolerDataTest() throws Exception
    {
        String ret="";
        //用DolerData判断
        long start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        for(int i=0;i<500;i++)
        {
            HashParam hs=new HashParam();
            hs.Add("Code","FileServiceAddr");
            hs.Add("ParaType","HOS");
            hs.Add("ParaTypeCode","1");
            if(EntityManager().DolerData(JRTParameter.class,hs))
            {
                //System.out.println("存在参数");
            }
        }
        long end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret="用DolerGet通过索引取数据耗时:"+(end-start);



        //不用DolerData判断
        start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        for(int i=0;i<500;i++)
        {
            HashParam hs=new HashParam();
            hs.Add("Code","FileServiceAddr");
            hs.Add("ParaType","HOS");
            hs.Add("ParaTypeCode","1");
            if(EntityManager().CheckHasData(JRTParameter.class,hs,null,null))
            {
                //System.out.println("存在参数");
            }
        }
        end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret+=",直接查数据库取数据耗时:"+(end-start);
        return ret;
    }

    /**
     * 用DolerGet通过唯一索引查询数据
     * @return
     */
    public String DolerIndexGet() throws Exception
    {
        String ret="";
        //带索引缓存查询测
        long start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        for(int i=0;i<5000;i++)
        {
            HashParam hs=new HashParam();
            hs.Add("Code","FileServiceAddr");
            hs.Add("ParaType","HOS");
            hs.Add("ParaTypeCode","1");
            JRTParameter para=EntityManager().DolerGet(JRTParameter.class,hs);
        }
        long end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret="用DolerGet通过索引取数据耗时:"+(end-start);

        //不带索引缓存查询测试
        start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        for(int i=0;i<5000;i++)
        {
            HashParam hs=new HashParam();
            hs.Add("Code","FileServiceAddr");
            hs.Add("ParaType","HOS");
            hs.Add("ParaTypeCode","1");
            JRTParameter para=EntityManager().GetByPara(JRTParameter.class,hs);
        }
        end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        ret+=",直接查数据库取数据耗时:"+(end-start);
        return ret;
    }


    /**
     * 不用DolerGet查询数据
     * @return
     */
    public String NoDolerGet() throws Exception
    {
        long start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        //查询所有表里面的元素
        List<JRTPrintTemplateEleRetDto> eleList=EntityManager().FindAllSimple(JRTPrintTemplateEleRetDto.class,null);
        int getNum=0;
        for(JRTPrintTemplateEleRetDto ele:eleList)
        {
            for(int i=0;i<2000;i++) {
                //取模板信息
                JRTPrintTemplate tmp = EntityManager().GetById(JRTPrintTemplate.class, ele.PrintTemplateDR);
                ele.TemplateCode=tmp.Code;
                ele.TemplateName=tmp.CName;
                //取纸张信息
                if(tmp.JRTPrintPaperDR!=null)
                {
                    JRTPrintPaper paper=EntityManager().GetById(JRTPrintPaper.class,tmp.JRTPrintPaperDR);
                    ele.TemplatePaper=paper.CName;
                    getNum++;
                }
                getNum++;
            }
        }
        long end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        return "消耗时间:"+(end-start)+",获取次数:"+getNum+",数据行数:"+eleList.size()+",数据:"+Helper.Object2Json(eleList);
    }

    /**
     * 用DolerGet查询数据
     * @return
     */
    public String DolerGet() throws Exception
    {
        long start=JRT.Core.Util.TimeParser.GetTimeInMillis();
        //查询所有表里面的元素
        List<JRTPrintTemplateEleRetDto> eleList=EntityManager().FindAllSimple(JRTPrintTemplateEleRetDto.class,null);
        int getNum=0;
        for(JRTPrintTemplateEleRetDto ele:eleList)
        {
            for(int i=0;i<2000;i++) {
                //取模板信息
                JRTPrintTemplate tmp = EntityManager().DolerGet(JRTPrintTemplate.class, ele.PrintTemplateDR);
                ele.TemplateCode=tmp.Code;
                ele.TemplateName=tmp.CName;
                //取纸张信息
                if(tmp.JRTPrintPaperDR!=null)
                {
                    JRTPrintPaper paper=EntityManager().DolerGet(JRTPrintPaper.class,tmp.JRTPrintPaperDR);
                    ele.TemplatePaper=paper.CName;
                    getNum++;
                }
                getNum++;
            }
        }
        long end=JRT.Core.Util.TimeParser.GetTimeInMillis();
        return "消耗时间:"+(end-start)+",获取次数:"+getNum+",数据行数:"+eleList.size()+",数据:"+Helper.Object2Json(eleList);
    }

    }
}


同时JRT把开发速度也提高到极致,业务脚本化方便开发和修改,开发环境简单到只要idea和jdk把环境部署简化。

借助实现的代码生成器为所有表生成拷贝的代码资源,Aspx和Java代码是直接放上去就能增删改查的界面,单表维护有特殊改动的只要基于生成基础改改,多表维护从里面拷贝素材。
在这里插入图片描述
这样的一个父子表维护界面的开发时间直接提速到半小时范围,拷贝父表界面和后台,加详细列弹窗,拷子表界面后后台逻辑组装。
在这里插入图片描述
生成页面示例

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
    <title>JRTMenu供拷贝代码使用</title>
    <link rel="shortcut icon" href="../../resource/common/images/favicon.ico" />
    <script src="../../resource/common/js/JRTBSBase.js" type="text/javascript"></script>
    <script language="javascript" type="text/javascript">
        SYSPageCommonInfo.Init();
        var BasePath = '';
        var ResourcePath = '';
        var WebServicAddress = SYSPageCommonInfo.Data.WebServicAddress;
        var UserID = SYSPageCommonInfo.Data.Sesssion.UserID;
        var GroupID = SYSPageCommonInfo.Data.Sesssion.GroupID;
        var SessionStr = SYSPageCommonInfo.Data.SessionStr;
    </script>
    <script type="text/javascript">
        //全局变量
        var me = {
            actionUrl: '../ashx/ashJRTMenu.ashx'
        };

        //jquery入口
        $(function () {

            //新增数据点击
            $("#btnAddJRTMenu").click(function () {
                $("#txtJRTMenuRowID").val(""); 
				$('#winEditJRTMenu').window({
                    title: TranslateDataMTHD('Add Data', '新增数据', ''),
                    modal: true
                });
            });


            //修改数据点击
            $("#btnUpdateJRTMenu").click(function () {
				UpdateJRTMenu();
            });

			//修改数据
			function UpdateJRTMenu(row)
			{
                var selectRow = $('#dgJRTMenu').datagrid("getSelected");
                if(row!=null)
                {
                	selectRow=row;
                }
                if (selectRow == null) {
                    $.messager.alert(TranslateDataMTHD('Info', '提示', ''), TranslateDataMTHD('Please select the data to modify', '请选择要修改的数据!', ''), 'info');
                    return;
                }
				$("#formJRTMenu").form('load', selectRow);
				$('#winEditJRTMenu').window({
                    title: TranslateDataMTHD('Update Data', '修改数据', ''),
                    modal: true
                });
			}



            //删除数据点击
            $("#btnDeleteJRTMenu").click(function () {
                var checkRow = $('#dgJRTMenu').datagrid("getChecked");
                var selectRow = $('#dgJRTMenu').datagrid("getSelected");
                if ((checkRow == null || checkRow.length == 0)&&selectRow==null) {
                    $.messager.alert(TranslateDataMTHD('Info', '提示', ''), TranslateDataMTHD('Please select the data to delete', '请勾选要删除的数据!', ''), 'info');
                    return;
                }
                if ((checkRow == null || checkRow.length == 0)) {
                    checkRow=[selectRow];
                }
                var RowIDS = "";
                for (var i = 0; i < checkRow.length; i++) {
                    if (i == 0) {
                        RowIDS = checkRow[i].RowID;
                    }
                    else {
                        RowIDS += "^" + checkRow[i].RowID;
                    }
                }
                $.messager.confirm(TranslateDataMTHD('Info', '提示', ''), TranslateDataMTHD('Do you want to delete the selected data', '是否要删除选择的数据?', '') , function (r) {
                    if (r) {
                		//开启等待
                		$.messager.progress({ text: TranslateDataMTHD("Deleting data","正在删除数据", ""), interval: 500 });
                		setTimeout(function () {
                    		$.messager.progress('close');
                		}, 8000);
                		//往后台提交数据
                		$.ajax({
                    		type: "post",
                    		dataType: "json",
                    		cache: false, //
                    		async: true, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
                    		url: me.actionUrl + '?Method=DeleteJRTMenu',
                    		data: { RowIDS: RowIDS },
                    		success: function (data, status) {
                        		$.messager.progress('close');
                        		if (!FilterBackData(data)) {
                            		return;
                        		}
                        		if (!data.IsOk) {
                            		$.messager.alert(TranslateDataMTHD("Error message", "错误提示", ""), TranslateDataMTHD("failed to dalete data, error message:", "删除失败,错误信息:", "") + data.Message);
                        		}
                        		else {
                            		QryJRTMenu();
                            		$.messager.show({
                                		title: TranslateDataMTHD("Info", "提示", ""),
                               		 	msg: TranslateDataMTHD("Successfully deleted!", "删除成功!", ""),
                                		timeout: 500,
                                		showType: 'slide'
                            		});
                        		}
                    		}
                		});
                    }
                });
            });


            //保存数据
            $("#btnSaveJRTMenu").click(function () {
                var saveData = jQuery.parseJSON($("#formJRTMenu").serializeObject());
                //开启等待
                $.messager.progress({ text: TranslateDataMTHD("Saving data","正在保存数据", ""), interval: 500 });
                setTimeout(function () {
                    $.messager.progress('close');
                }, 8000);
                //往后台提交数据
                $.ajax({
                    type: "post",
                    dataType: "json",
                    cache: false, //
                    async: true, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
                    url: me.actionUrl + '?Method=SaveJRTMenu',
                    data: saveData,
                    success: function (data, status) {
                        $.messager.progress('close');
                        if (!FilterBackData(data)) {
                            return;
                        }
                        if (!data.IsOk) {
                            $.messager.alert(TranslateDataMTHD("Error message", "错误提示", ""), TranslateDataMTHD("failed to save data, error message:", "保存失败,错误信息:", "") + data.Message);
                        }
                        else {
                            QryJRTMenu();
                            $.messager.show({
                                title: TranslateDataMTHD("Info", "提示", ""),
                                msg: TranslateDataMTHD("Successfully saveed!", "保存成功!", ""),
                                timeout: 500,
                                showType: 'slide'
                            });
                            $('#winEditJRTMenu').window("close");
                        }
                    }
                });
            });


            //关闭窗口
            $("#btnCloseJRTMenu").click(function () {
				$('#winEditJRTMenu').window("close");
            });


            //构造查询事件
            $("#txtFilterJRTMenu").searchbox({
                searcher: function (value, name) {
                    QryJRTMenu();
                },
                prompt: TranslateDataMTHD('Enter query', '回车查询', '')
            });



            //上级下拉表格渲染
            $('#txtJRTMenuParentDR').combogrid({
                panelWidth: 350,
                idField: 'RowID',
                width: 205,
                textField: 'CName',
                url: me.actionUrl + '?Method=CommonQueryView&data='+JSON.stringify({ ModelName: "JRTMenu", Pram: [], IsDisplayCount: false, Joiner: [], Operators: [] }),
                columns: [[
                    { field: 'RowID', title: '主键', width: 60 },
                    { field: 'CName', title: '名称', width: 260 }
                ]]
            });
            $('#txtJRTMenuParentDR').combogrid("showSelectWin");

            //页面路径下拉表格渲染
            $('#txtJRTMenuFormDR').combogrid({
                panelWidth: 350,
                idField: 'RowID',
                width: 205,
                textField: 'CName',
                url: me.actionUrl + '?Method=CommonQueryView&data='+JSON.stringify({ ModelName: "JRTForm", Pram: [], IsDisplayCount: false, Joiner: [], Operators: [] }),
                columns: [[
                    { field: 'RowID', title: '主键', width: 60 },
                    { field: 'CName', title: '名称', width: 260 }
                ]]
            });
            $('#txtJRTMenuFormDR').combogrid("showSelectWin");

            //激活布尔渲染
            $('#txtJRTMenuActive').combobox({
                valueField:'RowID',
                textField:'CName',
                width: 205,
                data: [{"RowID":false,"CName":TranslateDataMTHD('No', '否', '')},{"RowID":true,"CName":TranslateDataMTHD('Yes', '是', '')}]
            });

            //是否置顶显示布尔渲染
            $('#txtJRTMenuIsTop').combobox({
                valueField:'RowID',
                textField:'CName',
                width: 205,
                data: [{"RowID":false,"CName":TranslateDataMTHD('No', '否', '')},{"RowID":true,"CName":TranslateDataMTHD('Yes', '是', '')}]
            });

            //子系统下拉表格渲染
            $('#txtJRTMenuSystemSubDR').combogrid({
                panelWidth: 350,
                idField: 'RowID',
                width: 205,
                textField: 'SubSysName',
                url: me.actionUrl + '?Method=CommonQueryView&data='+JSON.stringify({ ModelName: "JRTSystemSub", Pram: [], IsDisplayCount: false, Joiner: [], Operators: [] }),
                columns: [[
                    { field: 'RowID', title: '主键', width: 60 },
                    { field: 'SubSysName', title: '名称', width: 260 }
                ]]
            });
            $('#txtJRTMenuSystemSubDR').combogrid("showSelectWin");

            //系统模块下拉表格渲染
            $('#txtJRTMenuSystemDR').combogrid({
                panelWidth: 350,
                idField: 'RowID',
                width: 205,
                textField: 'SysName',
                url: me.actionUrl + '?Method=CommonQueryView&data='+JSON.stringify({ ModelName: "JRTSystem", Pram: [], IsDisplayCount: false, Joiner: [], Operators: [] }),
                columns: [[
                    { field: 'RowID', title: '主键', width: 60 },
                    { field: 'SysName', title: '名称', width: 260 }
                ]]
            });
            $('#txtJRTMenuSystemDR').combogrid("showSelectWin");

            //JRTMenu表格
            $('#dgJRTMenu').datagrid({
                remoteSort:false,
                singleSelect: true,
                toolbar: "#dgJRTMenuToolBar",
                fit: true,
                onSelect: function (index, row) {
                    //方便拷贝到子表查询用
                	var selectJRTMenu=$('#dgJRTMenu').datagrid("getSelected");
                },
                onDblClickRow: function (index, row) {
                    UpdateJRTMenu(row);
                },

                columns: [[
                    { field: 'ChkFlag', title: TranslateDataMTHD('Check', '选择', ''), width: 20, sortable: true, align: 'center', checkbox: true },
                    { field: 'RowID', title: TranslateDataMTHD('RowID', '主键', '') , width: 150, sortable: true },
                    { field: 'CName', title: TranslateDataMTHD('CName', '名称', '') , width: 150, sortable: true },
                    { field: 'ParentDR_JRTMenu_CName', title: TranslateDataMTHD('ParentDR', '上级', '') , width: 150, sortable: true },
                    { field: 'FormDR_JRTForm_CName', title: TranslateDataMTHD('FormDR', '页面路径', '') , width: 150, sortable: true },
                    { field: 'Description', title: TranslateDataMTHD('Description', '功能描述', '') , width: 150, sortable: true },
                    { field: 'Icon', title: TranslateDataMTHD('Icon', '图标', '') , width: 150, sortable: true },
                    { field: 'Sequence', title: TranslateDataMTHD('Sequence', '序号', '') , width: 150, sortable: true },
                    { field: 'Active', title: TranslateDataMTHD('Active', '激活', '') , width: 150, sortable: true },
                    { field: 'IsTop', title: TranslateDataMTHD('IsTop', '是否置顶显示', '') , width: 150, sortable: true },
                    { field: 'SystemSubDR_JRTSystemSub_SubSysName', title: TranslateDataMTHD('SystemSubDR', '子系统', '') , width: 150, sortable: true },
                    { field: 'SystemDR_JRTSystem_SysName', title: TranslateDataMTHD('SystemDR', '系统模块', '') , width: 150, sortable: true },
                    { field: 'OpenModel', title: TranslateDataMTHD('OpenModel', '空:在Tab页打印,0:弹窗打开,1:独立打开', '') , width: 150, sortable: true },
                    { field: 'OpenWidth', title: TranslateDataMTHD('OpenWidth', '打开宽度', '') , width: 150, sortable: true },
                    { field: 'OpenHeight', title: TranslateDataMTHD('OpenHeight', '打开高度', '') , width: 150, sortable: true }
                ]]
            });


            //查询JRTMenu
            function QryJRTMenu() {
                var Filter = $("#txtFilterJRTMenu").searchbox("getValue");
                //开启等待,默认注释,在单击事件调用的逻辑启用等待会冲掉双击事件,按需要开启
                //$.messager.progress({ text: TranslateDataMTHD("Querying data","正在查询数据", ""), interval: 500 });
                //setTimeout(function () {
                    //$.messager.progress('close');
                //}, 8000);
                $.ajax({
                    type: "post",
                    dataType: "json",
                    cache: false, //
                    async: true, //为true时,异步,不等待后台返回值,为false时强制等待;-asir
                    url: me.actionUrl + '?Method=QryJRTMenu',
                    data: { Filter: Filter },
                    success: function (data, status) {
                        //结束等待
                        //$.messager.progress('close');
                        if (!FilterBackData(data)) {
                           return;
                        }
                        $('#dgJRTMenu').datagrid("loadData", data);
                    }
                });
            };


            //执行查询数据
            QryJRTMenu();


		});
    </script>
</head>
<body>
    <div class="easyui-layout" fit="true" style="border: none;">
        <div data-options="region:'center',title:''" style="border: none;">
            <div id="dgJRTMenuToolBar" style="padding: 3px 0px 3px 10px;">
                <a id="btnAddJRTMenu" href="#" class="easyui-linkbutton" data-options="iconCls:'icon-add'" plain="true" listranslate="html~Add">新增</a>
                <a id="btnUpdateJRTMenu" href="#" class="easyui-linkbutton" data-options="iconCls:'icon-write-order'" plain="true" listranslate="html~Mod">修改</a>
                <a id="btnDeleteJRTMenu" href="#" class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" plain="true" listranslate="html~Del">删除</a>
                <input id="txtFilterJRTMenu" style="margin-left: 14px; width: 240px;"></input>
            </div>
            <table id="dgJRTMenu" title="" iconcls="icon-paper" listranslate="title~JRTMenu"></table>
        </div>
        <div id="winEditJRTMenu" style="padding: 10px 0px 0px 10px;width:1140px;height:292.6666666666666667px;display: none;">
            <form id="formJRTMenu" name="edit_form" method="post">
                <input type="hidden" id="txtJRTMenuRowID" name="RowID" value="0" />
                <table>
                    <tr>
                        <td class="lisar" jrttranslate="html~CName">名称</td>
                        <td class="lisal"><input id="txtJRTMenuCName" type="text" name="CName" style="width:200px;" class="easyui-validatebox"  maxlength="20"/></td>
                        <td class="lisar" jrttranslate="html~ParentDR">上级</td>
                        <td class="lisal"><input id="txtJRTMenuParentDR" type="text" name="ParentDR" style="width:200px;"/></td>
                        <td class="lisar" jrttranslate="html~FormDR">页面路径</td>
                        <td class="lisal"><input id="txtJRTMenuFormDR" type="text" name="FormDR" style="width:200px;"/></td>
                    </tr>
                    <tr>
                        <td class="lisar" jrttranslate="html~Description">功能描述</td>
                        <td class="lisal"><input id="txtJRTMenuDescription" type="text" name="Description" style="width:200px;" class="easyui-validatebox"  maxlength="100"/></td>
                        <td class="lisar" jrttranslate="html~Icon">图标</td>
                        <td class="lisal"><input id="txtJRTMenuIcon" type="text" name="Icon" style="width:200px;" class="easyui-validatebox"  maxlength="100"/></td>
                        <td class="lisar" jrttranslate="html~Sequence">序号</td>
                        <td class="lisal"><input id="txtJRTMenuSequence" type="text" name="Sequence" style="width:200px;" class="easyui-validatebox"  maxlength="10"/></td>
                    </tr>
                    <tr>
                        <td class="lisar" jrttranslate="html~Active">激活</td>
                        <td class="lisal"><input id="txtJRTMenuActive" type="text" name="Active" style="width:200px;" class="easyui-validatebox"  maxlength="1"/></td>
                        <td class="lisar" jrttranslate="html~IsTop">是否置顶显示</td>
                        <td class="lisal"><input id="txtJRTMenuIsTop" type="text" name="IsTop" style="width:200px;" class="easyui-validatebox"  maxlength="1"/></td>
                        <td class="lisar" jrttranslate="html~SystemSubDR">子系统</td>
                        <td class="lisal"><input id="txtJRTMenuSystemSubDR" type="text" name="SystemSubDR" style="width:200px;"/></td>
                    </tr>
                    <tr>
                        <td class="lisar" jrttranslate="html~SystemDR">系统模块</td>
                        <td class="lisal"><input id="txtJRTMenuSystemDR" type="text" name="SystemDR" style="width:200px;"/></td>
                        <td class="lisar" jrttranslate="html~OpenModel">空:在Tab页打印,0:弹窗打开,1:独立打开</td>
                        <td class="lisal"><input id="txtJRTMenuOpenModel" type="text" name="OpenModel" style="width:200px;" class="easyui-validatebox"  maxlength="1"/></td>
                        <td class="lisar" jrttranslate="html~OpenWidth">打开宽度</td>
                        <td class="lisal"><input id="txtJRTMenuOpenWidth" type="text" name="OpenWidth" style="width:200px;" class="easyui-validatebox"  maxlength="10"/></td>
                    </tr>
                    <tr>
                        <td class="lisar" jrttranslate="html~OpenHeight">打开高度</td>
                        <td class="lisal"><input id="txtJRTMenuOpenHeight" type="text" name="OpenHeight" style="width:200px;" class="easyui-validatebox"  maxlength="10"/></td>
                    </tr>
                </table>
                <div region="south" border="fale" style="text-align: center; padding: 5px 0 0;">
                    <a id="btnSaveJRTMenu" href="#" class="easyui-linkbutton" plain="false" listranslate="html~Save">保存</a>
                    <span class="sp6"></span>
                    <a id="btnCloseJRTMenu" href="#" class="easyui-linkbutton" plain="false" listranslate="html~Cancel">取消</a>
                </div>
            </form>
        </div>
   </div>
</body>
</html>



生成的后台

import JRTBLLBase.BaseHttpHandler;
import JRTBLLBase.Helper;
import JRT.Core.Dto.HashParam;
import JRT.Core.Dto.ParamDto;
import JRT.Core.Dto.OutParam;
import JRT.Model.Entity.*;
import JRT.Core.Util.Convert;
import JRT.Core.MultiPlatform.JRTContext;

import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;

/**
*由代码生成器生成的后台代码
*/
public class ashJRTMenu extends BaseHttpHandler {

	/**
	 * 保存数据,前台按表的属性名提交
	 * @return 字符串
	 */
	public String SaveJRTMenu() throws Exception
    {
		JRTMenu dto=new JRTMenu();
		//主键  
		dto.RowID=Helper.ValidParam(JRTContext.GetRequest(Request, "RowID"), dto.RowID);
		//名称  
		dto.CName=Helper.ValidParam(JRTContext.GetRequest(Request, "CName"), dto.CName);
		//上级  
		dto.ParentDR=Helper.ValidParam(JRTContext.GetRequest(Request, "ParentDR"), dto.ParentDR);
		//页面路径
		dto.FormDR=Helper.ValidParam(JRTContext.GetRequest(Request, "FormDR"), dto.FormDR);
		//功能描述  
		dto.Description=Helper.ValidParam(JRTContext.GetRequest(Request, "Description"), dto.Description);
		//图标  
		dto.Icon=Helper.ValidParam(JRTContext.GetRequest(Request, "Icon"), dto.Icon);
		//序号  
		dto.Sequence=Helper.ValidParam(JRTContext.GetRequest(Request, "Sequence"), dto.Sequence);
		//激活  {1:true,0:false}
		dto.Active=Helper.ValidParam(JRTContext.GetRequest(Request, "Active"), dto.Active);
		//是否置顶显示  {1:true,0:false}
		dto.IsTop=Helper.ValidParam(JRTContext.GetRequest(Request, "IsTop"), dto.IsTop);
		//子系统
		dto.SystemSubDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemSubDR"), dto.SystemSubDR);
		//系统模块  
		dto.SystemDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemDR"), dto.SystemDR);
		//空:在Tab页打印,0:弹窗打开,1:独立打开  
		dto.OpenModel=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenModel"), dto.OpenModel);
		//打开宽度 
		dto.OpenWidth=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenWidth"), dto.OpenWidth);
		//打开高度
		dto.OpenHeight=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenHeight"), dto.OpenHeight);
		OutParam out=new OutParam();
		int ret=0;
		//更新
		if(dto.RowID>0)
		{
			ret=EntityManager().Update(dto,null, out, null, null, null);
		}
		//插入数据
		else
		{
			ret=EntityManager().Save(dto,out);
		}
		if(ret==1)
		{
			return Helper.Success();
		}
		else
		{
			return Helper.Error(out);
		}
    }



	/**
	 * 删除数据,多个RowID以上尖号分割
	 * @return 字符串
	 */
	public String DeleteJRTMenu() throws Exception
    {
		String RowIDS=Helper.ValidParam(JRTContext.GetRequest(Request, "RowIDS"), "");
		if(RowIDS.isEmpty())
		{
			return Helper.Error("请传入要删除数据的RowID,多个以^分割!");
		}
		//分割主键
		String [] arr=RowIDS.split("\\^");
		//out参数
		OutParam out=new OutParam();
		//循环删除数据
		for(int i=0;i<arr.length;i++)
		{
			int ret=EntityManager().RemoveById(JRTMenu.class,Convert.ToLong(arr[i]),out);
			if(ret!=1)
			{
				return Helper.Error(out);
			}
		}
		return Helper.Success();
	}



	/**
	 * 查询数据,前台按表的属性名提交
	 * @return 字符串
	 */
	public String QryJRTMenu() throws Exception
    {
		//预留的取前台参数代码
		//参数
		List<ParamDto> para=new ArrayList<>();
		//sql连接符号
		List<String> joiner=new ArrayList<>();
		//sql比较符号
		List<String> operators=new ArrayList<>();
		//模糊查询
		String Filter=Helper.ValidParam(JRTContext.GetRequest(Request, "Filter"), "");
		//预留参数
		//主键  
		String RowID=Helper.ValidParam(JRTContext.GetRequest(Request, "RowID"), "");
		//名称  
		String CName=Helper.ValidParam(JRTContext.GetRequest(Request, "CName"), "");
		//上级  
		String ParentDR=Helper.ValidParam(JRTContext.GetRequest(Request, "ParentDR"), "");
		//页面路径
		String FormDR=Helper.ValidParam(JRTContext.GetRequest(Request, "FormDR"), "");
		//功能描述  
		String Description=Helper.ValidParam(JRTContext.GetRequest(Request, "Description"), "");
		//图标  
		String Icon=Helper.ValidParam(JRTContext.GetRequest(Request, "Icon"), "");
		//序号  
		String Sequence=Helper.ValidParam(JRTContext.GetRequest(Request, "Sequence"), "");
		//激活  {1:true,0:false}
		String Active=Helper.ValidParam(JRTContext.GetRequest(Request, "Active"), "");
		//是否置顶显示  {1:true,0:false}
		String IsTop=Helper.ValidParam(JRTContext.GetRequest(Request, "IsTop"), "");
		//子系统
		String SystemSubDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemSubDR"), "");
		//系统模块  
		String SystemDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemDR"), "");
		//空:在Tab页打印,0:弹窗打开,1:独立打开  
		String OpenModel=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenModel"), "");
		//打开宽度 
		String OpenWidth=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenWidth"), "");
		//打开高度
		String OpenHeight=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenHeight"), "");
		//模糊查询
		if(!Filter.isEmpty())
		{
			ParamDto p=null;
			//名称  
			p=new ParamDto();
			p.Key="CName";
			p.Value="%"+Filter+"%";
			para.add(p);
			joiner.add("or");
			operators.add("like");
			//功能描述  
			p=new ParamDto();
			p.Key="Description";
			p.Value="%"+Filter+"%";
			para.add(p);
			joiner.add("or");
			operators.add("like");
			//图标  
			p=new ParamDto();
			p.Key="Icon";
			p.Value="%"+Filter+"%";
			para.add(p);
			joiner.add("or");
			operators.add("like");
			//空:在Tab页打印,0:弹窗打开,1:独立打开  
			p=new ParamDto();
			p.Key="OpenModel";
			p.Value="%"+Filter+"%";
			para.add(p);
			joiner.add("or");
			operators.add("like");
		}
		//调用查询
		String json=EntityManager().QueryAllWithFK(JRTMenu.class,para,"",true,-1,-1,"",joiner,operators);
		return json;
	}



	/**
	 * 查询数据,前台按表的属性名提交
	 * @return 字符串
	 */
	public String FindJRTMenu() throws Exception
    {
		List<HashMap> retList=new ArrayList<>();
		//参数
		HashParam hs=new HashParam();
		//模糊查询
		String Filter=Helper.ValidParam(JRTContext.GetRequest(Request, "Filter"), "");
		//预留参数
		//主键  
		String RowID=Helper.ValidParam(JRTContext.GetRequest(Request, "RowID"), "");
		//名称  
		String CName=Helper.ValidParam(JRTContext.GetRequest(Request, "CName"), "");
		//上级  
		String ParentDR=Helper.ValidParam(JRTContext.GetRequest(Request, "ParentDR"), "");
		//页面路径
		String FormDR=Helper.ValidParam(JRTContext.GetRequest(Request, "FormDR"), "");
		//功能描述  
		String Description=Helper.ValidParam(JRTContext.GetRequest(Request, "Description"), "");
		//图标  
		String Icon=Helper.ValidParam(JRTContext.GetRequest(Request, "Icon"), "");
		//序号  
		String Sequence=Helper.ValidParam(JRTContext.GetRequest(Request, "Sequence"), "");
		//激活  {1:true,0:false}
		String Active=Helper.ValidParam(JRTContext.GetRequest(Request, "Active"), "");
		//是否置顶显示  {1:true,0:false}
		String IsTop=Helper.ValidParam(JRTContext.GetRequest(Request, "IsTop"), "");
		//子系统
		String SystemSubDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemSubDR"), "");
		//系统模块  
		String SystemDR=Helper.ValidParam(JRTContext.GetRequest(Request, "SystemDR"), "");
		//空:在Tab页打印,0:弹窗打开,1:独立打开  
		String OpenModel=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenModel"), "");
		//打开宽度 
		String OpenWidth=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenWidth"), "");
		//打开高度
		String OpenHeight=Helper.ValidParam(JRTContext.GetRequest(Request, "OpenHeight"), "");
		//模糊查询
		if(!Filter.isEmpty())
		{
			ParamDto p=null;
			//名称  
			hs.Add("CName","%"+Filter+"%","","","like","or");
			//功能描述  
			hs.Add("Description","%"+Filter+"%","","","like","or");
			//图标  
			hs.Add("Icon","%"+Filter+"%","","","like","or");
			//空:在Tab页打印,0:弹窗打开,1:独立打开  
			hs.Add("OpenModel","%"+Filter+"%","","","like","or");
		}
		//调用查询
		List<JRTMenu> allList=EntityManager().FindAllSimple(JRTMenu.class,hs);
		if(allList!=null&&allList.size()>0)
		{
			for(JRTMenu one:allList)
			{
				HashMap out=new HashMap();
		        //主键  
				out.put("RowID",one.RowID);
		        //名称  
				out.put("CName",one.CName);
		        //上级  
				out.put("ParentDR",one.ParentDR);
				out.put("ParentName",EntityManager().DolerGetCName(JRTMenu.class,one.ParentDR));
		        //页面路径
				out.put("FormDR",one.FormDR);
				out.put("FormName",EntityManager().DolerGetCName(JRTForm.class,one.FormDR));
		        //功能描述  
				out.put("Description",one.Description);
		        //图标  
				out.put("Icon",one.Icon);
		        //序号  
				out.put("Sequence",one.Sequence);
		        //激活  {1:true,0:false}
				out.put("Active",one.Active);
		        //是否置顶显示  {1:true,0:false}
				out.put("IsTop",one.IsTop);
		        //子系统
				out.put("SystemSubDR",one.SystemSubDR);
				out.put("SystemSubSubSysName",Helper.ToStr(EntityManager().DolerGetCol(JRTSystemSub.class,one.SystemSubDR,"SubSysName")));
		        //系统模块  
				out.put("SystemDR",one.SystemDR);
				out.put("SystemSysName",Helper.ToStr(EntityManager().DolerGetCol(JRTSystem.class,one.SystemDR,"SysName")));
		        //空:在Tab页打印,0:弹窗打开,1:独立打开  
				out.put("OpenModel",one.OpenModel);
		        //打开宽度 
				out.put("OpenWidth",one.OpenWidth);
		        //打开高度
				out.put("OpenHeight",one.OpenHeight);
				retList.add(out);
			}
		}
		return Helper.Object2Json(retList,true);
		
	}


}

JRT源自Cache、探索于C#、落地于Java。带来的不仅仅是技术的革新,更是思想和设计的革新,充分理解数据的28原则,以四两拨千斤的思路改进关系库的多维查询瓶颈。今天我们在lis里面运用这样的架构,明天就有可能在整个医疗乃至信创里推广这样的架构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1976789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.怎么配置一个axios来拦截前后端请求

首先创建一个axios.js文件 导入我们所需要的依赖 import axios from "axios"; import Element from element-ui import router from "./router"; 设置请求头和它的类型和地址 注意先注释这个url,还没有解决跨域问题,不然会出现跨域 // axios.defaults.…

6-5 多输入多输出通道

虽然我们在前面描述了构成每个图像的多个通道和多层卷积层。例如彩色图像具有标准的RGB通道来代表红、绿和蓝。 但是到目前为止&#xff0c;我们仅展示了单个输入和单个输出通道的简化例子。 这使得我们可以将输入、卷积核和输出看作二维张量。 当我们添加通道时&#xff0c;我…

搭建高可用OpenStack(Queen版)集群(一)之架构环境准备

一、搭建高可用OpenStack&#xff08;Queen版&#xff09;集群之架构环境准备 一、架构设计 二、初始化基础环境 1、管理节点创建密钥对&#xff08;方便传输数据&#xff09; 所有控制节点操作 # ssh-keygen #一路回车即可 Generating public/private rsa key pair. Enter f…

MTK Android12 分析system_app允许vendor_mtk_audiohal_prop SELinux 权限问题

本文将尝试分析&#xff0c;在开发 Android 12 MTK 平台时遇到了 vendor_mtk_audiohal_prop 属性相关的 SELinux 权限问题。包括如何修改 SELinux 策略以允许 system_app 设置 vendor_mtk_audiohal_prop 属性。 问题描述 希望允许 system_app 设置 vendor_mtk_audiohal_prop 属…

SpringBoot+Vue图书(图书借阅)管理系统-附项目源码与配套文档

摘 要 本论文阐述了一套先进的图书管理系统的设计与实现&#xff0c;该系统采用Java语言&#xff0c;结合现代Web开发框架和技术&#xff0c;旨在为图书馆提供高效、灵活且用户友好的资源管理解决方案。系统利用Spring Boot框架为核心&#xff0c;整合MyBatis ORM工具&#…

基于 systemc-2.3.1的virtual device 接入 qemu-arm

1&#xff0c;下载systemc-2.3.1 下载网址&#xff1a; SystemC Files $ wget https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.1.tgz 2&#xff0c;编译安装 systemc-2.3.1 tar zxf systemc-2.3.1.tgz cd systemc-2.3.1/ export CXXg mkdir bu…

PS 2024 百种常用插件下载安装教程【免费使用,先到先得】

文章目录 软件介绍软件下载安装步骤 专栏推荐&#xff1a; 超多精品软件&#xff08;持续更新中…&#xff09; 软件推荐&#xff1a; PS 2024 PR 2024 软件介绍 PS常用插件 此软件整合了市面近百款ps处理插件&#xff0c;可实现&#xff1a;一键制作背景&#xff0c;一键抠图…

linux安装docker(实操教程)

一、安装前准备工作 1.查看服务器操作系统版本 2.查看服务器的操作系统内核版本 3.安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2如果不是root用户登陆的系统&#xff0c;需要手动输入sudo -i切换到root帐户 4.设置阿里云docker-ce镜像源 yum-c…

美国失业率大幅上升,增加九月份降息利率的可能性

令人失望的是&#xff0c;美国7月份经济增加了11.4万个工作岗位&#xff0c;低于预期的17.5万个和6月的17.9万个。平均小时工资持续下降&#xff0c;但失业率升至4.3%。美元继续走低&#xff0c;美国国债也在下跌&#xff0c;而黄金则获得了提振。 7月份的非农业支付数据令人失…

ST语言支持包下载安装(VS CODE)

VSCODE是微软提供的代码编辑器&#xff0c;支持非常多的语言。 1、VSCODE下载 2、ST语言支持包 3、ST语言支持包下载 4、ST语言 。。

IndentationError: expected an indented block 深度解析

IndentationError: expected an indented block 深度解析与实战指南 在Python编程中&#xff0c;IndentationError: expected an indented block是一个常见的错误&#xff0c;通常发生在代码块没有正确缩进时。这个错误表明代码中存在格式问题&#xff0c;可能是缩进不一致或缺…

基于PFC和ECN搭建无损RoCE网络的工作流程分析

无损RoCE网络概念 RDMA&#xff08;Remote Direct Memory Access&#xff0c;远程直接内存访问&#xff09;是一种为了解决网络传输中服务器端数据处理延迟而产生的技术。RDMA 将用户应用中的数据直接传入服务器的存储区&#xff0c;通过网络将数据从一个系统快速传输到远程系…

力扣421.数组中两个数的最大异或和

力扣421.数组中两个数的最大异或和 __builtin_clz()&#xff1a;求出mx二进制最高位之后的0的个数 class Solution {public:int findMaximumXOR(vector<int>& nums) {int mx *max_element(nums.begin(),nums.end());//__builtin_clz函数int high_bit mx ? 31 -…

单元测试JUnit

前言&#x1f440;~ 上一章我们介绍了自动化测试工具Selenium&#xff0c;今天讲解单元测试工具JUnit JUnit JUnit的使用 JUnit注解 BeforeAll和AfterAll注解 BeforeEach和AfterEach注解 参数化 方法获取参数&#xff08;动态参数&#xff09; 断言 用例执行顺序 测…

詹妮弗洛佩兹度过一个单身的季节!知情人:双方无法达成妥协,可能几日内将递交离婚申请!

对于詹妮弗洛佩兹来说&#xff0c;这是一个单身的季节&#xff0c;但这似乎并不是她希望从分居的丈夫本阿弗莱克那里得到的。当她在东海岸的汉普顿度过夏天时&#xff0c;这位 51 岁的演员正忙着在西海岸购买价值 2050 万美元的房产。洛佩兹显然认为&#xff0c;尽管他们已经分…

常见的CMS漏洞解析!

PhPMyadmin&#xff1a; 姿势⼀&#xff1a;通过日志文件拿Shell 利用mysql日志文件写shell&#xff0c;这个日志可以在mysql里改变它的存放位置&#xff0c;登录phpmyadmin可以修改 这个存放位置&#xff0c;并且可以修改它的后缀名。所以可以修改成php的后缀名就能获取⼀个…

通讯协议原始指令日志Python脚本分析

一.通讯协议格式&#xff1a; 二.通讯协议原始日志 [2024-04-18 14:58:59.659 D] 99 99 0E 00 01 0A 04 00 01 00 00 00 1E FN FN [2024-04-18 14:58:59.959 D] 99 99 0E 00 01 0C 03 03 01 00 BC FN FN 三.通讯协议原始指令日志Python脚本分析&#xff08;仅解析指令的PC版和…

反制攻击者-蚁剑低版本

目录 安装 攻击者获取防守方的权限 防守方反制攻击者 防守方获取攻击者的shell权限 安装 安装蚁剑2.0.7版本 链接&#xff1a;https://pan.baidu.com/s/1t40UxkZ2XuSWG6VCdGzvDw?pwd8888 提取码&#xff1a;8888 下载好后先打开Loader文件夹下的.exe文件&#xff0c;打…

常见cms漏洞之dedecms

DedeCMS是织梦团队开发PHP 网站管理系统&#xff0c;它以简单、易用、高效为特色&#xff0c;组建出各种各样各具特色的网站&#xff0c;如地方门户、行业门户、政府及企事业站点等。 下载地址请网上自行寻找 搭建方式选择php study 首先搭建环境 #前台http://localhost/dedecm…

医院患者押金原路退回系统源码,一键操作秒到账,无需设备收银设备 押金+身份证+电子押金单 解决方案

科技之力赋能医院押金原路退回&#xff0c;安全可靠账目清晰 一、医院押金管理必要性 以下是一些可用于销售软件、突出医院管理方便的优点总结&#xff1a; 1. 高效便捷的押金原路退回流程&#xff1a;利用科技之力&#xff0c;简化操作&#xff0c;节省时间和人力成本&#…