电脑桌面
添加蚂蚁七词文库到电脑桌面
安装后可以在桌面快捷访问

U8Cloud开发课件-红皮书-U8 cloud V1.0-公式技术红皮书.pdfVIP免费

U8Cloud开发课件-红皮书-U8 cloud V1.0-公式技术红皮书.pdf_第1页
1/44
U8Cloud开发课件-红皮书-U8 cloud V1.0-公式技术红皮书.pdf_第2页
2/44
U8Cloud开发课件-红皮书-U8 cloud V1.0-公式技术红皮书.pdf_第3页
3/44
红皮书-1.0公式技术新一代云ERP解决方案2目录一.新版公式使用手册.41.1.公式主要功能.41.2.公式的基本使用方法..51.3.数值型计算结果小数位的控制..91.4.自定义变量的使用.101.5.如何从公式中提取变量.121.6.空值””,NULL值及Zero值的处理.141.7.如何进行列操作..161.8.利用定义函数扩展公式功能.171.9.外接函数的使用..181.10.配置装载自定义函数.181.11.运算符重载..191.12.公式简单调试.211.13.公式使用最佳实践.22附录:公式解析器内置公式列表..271.数学运算函数.272.条件判断函数.313.数据库查询函数.334.字符串相关函数.355.日期函数..376.类型转换函数.377.货币金额函数.388.多语言翻译函数.419.其他函数..41新一代云ERP解决方案310.新增函数.42新一代云ERP解决方案4一.新版公式使用手册1.1.公式主要功能1.支持一般的算术运算+,-,*,/,ˆ,%例如:sin(1.35)*a/b+cos(3.4)/c其中a,b,c均为变量2.支持对数值型计算结果小数位的控制3.支持逻辑运算符&&(兼容老版&),||(兼容老版|),!例如:iif((a&b)||(c&&d),-right-,-wrong-)其中a,b,c,d均为变量4.支持比较运算符>,>=,<,<=,==,!=等,支持null值的处理。例如:iif((a>b&&a!=null)||(c<=d),-right-,-wrong-)其中a,b,c,d均为变量5.支持自定义变量,变量可按Object和String两种方式传入例如:col1->var1+var2其中var1,var2均为自定义变量,可以为String型,也可以为任意类型6.公式除了支持String,Number型数据运算,还支持自定义类型例如:combine(vo1,vo2)其中vo1,vo2可为自定义的数据类型,具体用法参考后面的说明7.支持操作符(+,-,*,/,>,>=,<,<=,==)重载(通过实现相应的接口)例如:iif((car1>car2)||(factory1<=factory2),-right-,-wrong-)其中car1,car2,factory1,factory2的运算符通过实现相应的接口进行重载。8.可以在数值型一维数组之间进行加减乘除运算(数组长度必须相等),即支持列操作.例如var1=[1,2,3,4];var2=[2,3,4,5];可对var1,var2进行各种运算。9.系统函数支持,U8C常用函数支持例如:sin,cos,ceil,floor,toChinese,getChineseCurrency(),iif()等等,详细支持的函数请参见附录。新一代云ERP解决方案510.支持外接用户函数.(可以是一个java的方法)例如:公式combine(-nihao-,-hao-)中,combine是一个自定义函数,可以指定绑定到一个JAVA类的具体方法,可参考后面的例子。11.支持自定义函数.具体应用可参考后面的详细说明(第17页第1.8节)有时候公式解析器内部的函数并不能完全满足用户的要求,此时用户可添加自定义函数。例如:hello(-saysomething-,person),hello为一个自定义函数,动态注册到公式解析器中。12.支持客户端公式和服务端公式.以满足前台及后台调用,主要体现在数据库查询的方式上有一定的差别。13.支持多行公式批量运算,且保持变量的传递性.例如:a->col1+col2;b->a+col1*col3;c->a+b;14.支持一个线程内多个公式执行器实例交替运行的情况,但不支持多个线程内同一公式执行器实例交替运行。所以如果程序中起多线程的话,建议每个线程单独创建自己的公式解析器示例。例如下面的代码是可行的:FormulaParseFatherf=newFormulaParse();f.setExpress(formula);f.setNullAsZero(true);FormulaParseFatherf1=newFormulaParse();f1.setNullAsZero(false);f.setDataSArray(map);String[]res=f.getValueS();15.支持单表查询类公式的自动SQL合并,极大提高查询效率。1.2.公式的基本使用方法使用公式解析器的基本步骤如下:新一代云ERP解决方案61.创建公式执行器如果在客户端使用公式解析:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();如果在服务端使用公式解析:FormulaParseFatherf=newnc.bs.pub.formulaparse.FormulaParse();如果不知道当前的代码会在哪一端运行,可以用下面的方法进行判断:if(RuntimeEnv.getInstance().isRunningInServer()){parse=newnc.bs.pub.formulaparse.FormulaParse();}else{parse=newnc.ui.pub.formulaparse.FormulaParse();}如果在客户端执行公式,但是又不希望使用前台缓存(注:在前台通过公式查询跨公司大数据档案时会严重影响LFU算法效果,导致前台缓存数据量急剧增加,影响缓存的稳定性,此种场景下不建议在前台执行公式,所以U8C报表类执行公式要求不走前台缓存),可以使用:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParseRunInServer();2.设置公式执行器环境(自定义变量及自定义函数可参考后续章节描述)这里可以给公式执行器添加自定义变量,例如:UFDoublevar1=newUFDouble(5.368);f.addVariable(var1);或者添加自定义函数,例如:类YourFunction是一个定义的函数类(关于如何自定义函数,请参考自定义函数一节),在公式中函数取名为-yourfun-,则可以这样添加你的自定义函数:f.addFunction(-yourfun-,newYourFunction);3.设置公式的值设置公式执行器环境非必须步骤对于单行公式:新一代云ERP解决方案7Stringfomula=-sin(30)*2-56/78-;f.setExpress(fomula);对于多行公式:String[]formulas=newString[]{-viewmny1->viewnum*viewprice-rate*0.23-,-viewmny2->viewnum*viewprice-rate*0.24-};f.setExpressArray(formulas);4.对公式进行语法检查在设置完公式之后,直接调用执行器的check()方法便可以进行公式检查:boolisok=f.check();如果返回结果为false,那么说明公式存在语法错误,调用getError()可以获得具体的错误信息:Stringerrmsg=f.getErrorMsg();下面是一段具体应用的代码:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();Stringformula=-a->getChineseCurrency(cchmny,34)-;booleanisok=f.check();if(!isok){System.out.println(f.getError());return;}另外,如果还没有设置公式,仅仅是想校验公式的正确性,则可以直接通过checkExpress(Stringformula)或者checkExpressArray(formulas)来检查公式,例如:boolisok=f.checkExpress(formulas);//单行公式boolisok=f.checkExpressArray(formulas);//多行公式注意:如果是多行公式,那么只要有一个公式写法是错误的,那么检查结果就会是false。5.提取公式变量在单据模板和打印模板的应用中,公式中的变量并不是已知的,需要从公式中分析得到,新一代云ERP解决方案8取得公式中的变量之后,再把相应的值赋给变量。新版公式解析器中提取公式中变量的接口和老版是一致的:VarryVO[]varrys=f.getVarryArray();下面是单据模板里取公式变量的典型代码://设置表达式formulas=filterUsedFormulas(bfc,formulas);if(formulas==null)returnnull;f.setExpressArray(formulas);//获得变量名finalVarryVO[]varrys=f.getVarryArray();6.给公式变量赋值下面是一段给公式变量赋值的代码://下列代码假设varrys不会为nullVarryVO[]varrys=f.getVarryArray();for(inti=0;i<varrys.length;i++){String[]varries=varrys[i].getVarry();//提取公式变量非必须步骤if(varries!=null){for(intj=0;j<varries.length;j++){//从外部环境取得变量的值ObjectvarryValue=getVarryValue(varries[j]);//传递给公式f.addVariable(varries[i],varryValue);}}}新一代云ERP解决方案97.取得公式的值根据公式具体的应用场景,取值有多种形式,如下所示:单行公式返回单个值:Objectres=f.getValueAsObject();单行公式返回一列值:Object[]res=f.getValueO();多行公式返回多列值:Object[][]res=f.getValueOArray();单行公式返回单个字符串Stringres=f.getValue();单行公式返回一列字符串:String[]res=f.getValueS();多行公式返回多列字符串String[][]res=f.getValueOArray();1.3.数值型计算结果小数位的控制当利用公式解析器进行数值型的运算时,可以对输出结果的小数位进行控制。公式解析器中提供了以下几个接口:publicvoidsetScale(intscale);设置返回精度,截位默认为四舍五入。对Double,UFDouble型返回结果有效。publicvoidsetScale(intscale,introundingup);设置返回精度及截位规则,对Double,UFDouble型返回结果有效。publicvoidsetScale(Stringvarname,intscale);针对具体的变量设置返回精度,截位默认为四舍五入。publicvoidsetScale(Stringvarname,intscale,introundingup);针对具体的变量设置返回精度及截位规则,对所有数值型返回结果有效。如果不做任何设置,那么输出结果与UFDouble的默认精度一致,为8位小数。下面是一个具体的示例:新一代云ERP解决方案10FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();String[]formulas=newString[]{-a->cchmny*cchmny*cchmny-,-b->a*cchmny-,-c->a*b*cchmny-};f.setExpressArray(formulas);Mapmap=newHashMap();Listv2=newArrayList();v2.add(newUFDouble(1.99999));//rowvaluev2.add(newUFDouble(2.9999));//rowvaluev2.add(newUFDouble(3.99999));v2.add(newUFDouble(1.999994));//rowvaluemap.put(-cchmny-,v2);f.setDataSArray(map);f.setScale(-a-,5);f.setScale(-b-,6);Object[][]res=f.getValueOArray();assertEquals(-应该相等!-,-7.99988-,res[0][0].toString());assertEquals(-应该相等!-,-15.999680-,res[1][0].toString());//默认精度为8assertEquals(-应该相等!-,-255.98976018-,res[2][0].toString());1.4.自定义变量的使用公式支持自定义变量,只要相关的操作允许的话,自定义变量可以是任何类型的,下面的代码说明了如何加入一个名为var1,UFDouble型的变量:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();Stringformula=-a->round(var1,3)-;f.addVariable(-var1-,newUFDouble(3.56893));新一代云ERP解决方案11除了可以加入简单类型的变量,还可以加入ArrayList3,用户自定义对象4等等,下面的代码演示了如何加入一个ArrayList型的变量:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();Stringformula=-a->round(var1,3)-;Listlist1=newArrayList();list1.add(newUFDouble(56.2354));list1.add(newUFDouble(23.2343));f.addVariable(-var1-,list1);另外还可以批量的加入多个变量,公式解析器提供两个接口如下:setDataSArray(Hashtable[]);//老版接口要求,不推荐使用setDataSArray(Map);需要注意的是,由于老版接口setDataSArray(Hashtable[])所有的参数均通过字符串传入,所以在以此方式传入参数时,存在真假字符串之分,真字符串形如:v1[0]=-\-SHVO0000000000000005\--;v1[1]=-\-SHVO0000000000000005\--;v1[2]=-\-SHVO0000000000000005\--;即在字符串的两端加上双引号”,表示传入的参数为String类型,如果两端不加这个符号,则表示传入的为数值型,公式解析器会将其转换为数值型处理,例如:v1[0]=-623.23-;v1[1]=-5263.12-;v1[2]=-5242.01-;而如果通过addVariable(name,Value)或者以setDataSArray(Map)方式传入参数时,参数的类型取决于实际传入的类型,公式解析器不会做任何转换:-),请注意下面两段代码的差别。老版公式接口,判断真假字符串:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setExpress(-a->var1+var2-);Listv2=newArrayList();v2.add(-100-);//rowvaluev2.add(-200-);//rowvalue新一代云ERP解决方案12Hashtablemap=newHashtable();map.put(-var1-,v2);map.put(-var2-,v2);Hashtable[]maps=newHashtable[1];maps[0]=map;f.setDataSArray(maps);//将会转为数值f.setScale(2);String[]res=f.getValueS();assertEquals(-Shouldequal:-,-200.00-,res[0].toString());新版增加的接口,传什么就是什么,完全按Object方式传递参数:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setExpress(-a->var1+var2-);Listv2=newArrayList();v2.add(-100-);//rowvaluev2.add(-200-);//rowvalueMapmap=newHashMap();map.put(-var1-,v2);map.put(-var2-,v2);f.setDataSArray(map);//当作字符串f.setScale(2);String[]res=f.getValueS();assertEquals(-Shouldequal:-,-100100-,res[0].toString());注意:公式中的变量取名不可与内置自定义变量名(可参考第25页第2章内置变量列表)相同,也不得与内置的函数名(可参考第26页第3章内置变量列表)相同,如果和内置变量相同,公式解析可能会得到不正确的结果;如果变量和内置函数名相同,则会报公式解析错误。1.5.如何从公式中提取变量单据模板和打印模板的公式解析要求可以解析识别公式中的列变量,以便从模板中取得相应的值赋给这些列变量。比如对下面的公式:新一代云ERP解决方案13String[]formulas=newString[]{-viewcode->getColValue(hyca_viewobj,viewcode,pk_viewobj,pk_viewobj)-,-viewchinaname->getColValue(hyca_viewobj,viewchinaname,pk_viewobj1,pk_viewobj1)-,-summny->cchmny*25/5+cchmny-}FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setExpressArray(formulas);得到的varrys的信息如下:varrys[0]:formulaName:viewcode;varry[1]:pk_viewobjvarrys[1]:formulaName:viewchinaname;varry[1]:pk_viewobj1varrys[2]:formulaName:summny;varry[1]:cchmny其中VarryVO的定义如下:publicclassVarryVO{StringformulaName=null;//公式名:等号左边String[]varry=null;//变量,等号右边的变量}利用varrys的信息就可以从模板中取得相应列变量的值,并将公式返回的值赋给每行公式左边列名所对应的列。下面是提取变量的另一个例子,演示了从复杂的函数中提取列变量:String[]formulas=newString[]{-viewcode->hyca_viewobj*cvn(hyca_viewobj,viewcode,pk_viewobj,pk_viewobj)+viewcode*cvs(hyca_viewobj,viewcode,pk_viewobj,pk_viewobj1)-,-viewchinaname->getColNmV(hyca_viewobj,viewchinaname,pk_viewobj,pk_viewobj2)-新一代云ERP解决方案14};FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setExpressArray(formulas);VarryVO[]varrys=f.getVarryArray();assertEquals(-应该相等!-,2,varrys.length);assertEquals(-应该相等!-,4,(varrys[0].getVarry()).length);1.6.空值””,NULL值及Zero值的处理在公式解析中,请注意区分以下三个概念:空值:指长度为0的字符串,--NULL值:指没有分配任何空间的Object,类似JAVA语言里的NULLZero值:指Double(0)公式执行器有一个共有函数setNullAsZero(booleanvalue),用于设置在运算过程中是否需要将NULL值作为Zero值来进行运算。默认状态下,公式执行器设置setNullAsZero(false)。请看下面的例子:Stringformula[]=newString[]{-a->val1/val2-,-b->val1*val2-};FormulaParseFatherf=newFormulaParse();f.addVariable(-val1-,null);f.addVariable(-val2-,newDouble(56));f.setExpressArray(formula);f.setNullAsZero(true);//设置为trueString[][]res=f.getValueSArray();//val1当做Double(0)计算,得出a=0assertEquals(-应该相等!-,-0.00000000-,res[0][0]);//val1当做Double(0)计算,得出b=0新一代云ERP解决方案15assertEquals(-应该相等!-,-0.00000000-,res[1][0]);如果上例中setNullAsZero(false),因为null值无法参与运算,那么得到的结果为空。对于setNullAsZero函数,需要注意的是,NULL值当作Zero值来处理仅仅是指在运算过程中,不适用于返回值为NULL时的处理,例如:Stringformula[]=-a->val1-;FormulaParseFatherf=newFormulaParse();f.addVariable(-val1-,null);f.setExpress(formula);f.setNullAsZero(true);Stringres=f.getValue();//val1当做Double(0)计算,但结果res为空值.如果上例中,想要返回0,则可以这么改写公式:Stringformula[]=-a->toNumber(val1)-;FormulaParseFatherf=newFormulaParse();f.addVariable(-val1-,null);f.setExpress(formula);f.setNullAsZero(true);Stringres=f.getValue();//结果res为0.00000000.当NULL值参与字符串连接时,NULL值自动被当作空值处理,setNullAsZero此时对运算结果无任何影响,例如:null+-dddd-+null;null+null+-dddd-;上述两个公式均应该返回-dddd-!关于NULL值,空值之间区别另一个需要注意的地方是在写IIF函数时,比较条件到底是NULL还是空值,需要根据实际场景决定,一般getColValue()等数据库查询函数如果无法查到值返回的是null值。例如:fkdw->iif(val2==null,-val2iszero-,val2)-;新一代云ERP解决方案16fkdw->iif(val2==--,-val2iszero-,val2)-;iif(getColValue(hyca_viewobj,viewchinaname,pk_viewobj,pk_viewobj)==null,pk_viewobj,getColValue(hyca_viewobj,viewchinaname,pk_viewobj,pk_viewobj));1.7.如何进行列操作公式支持列操作,即列之间的+,-,*,/,%,>,<,>=,<=,==等,需要注意的是这里的公式中的列均由ArrayList表示,如果加入自定义变量时,如果需要加入一列数据,需以ArrayList的形式加入!列操作的两个对象要求长度必须相等,实际上是对两个列的对应元素进行操作.例如:[1,2,3,4,5]+[3,3,4,5,6]=[4,5,7,9,11][4,6,8,9,45]/[2,3,4,3,9]=[2,2,2,3,5]列操作的目的主要是对模板上各列进行操作,以便可以在各列之间进行灵活的运算。比如有三个列分别为currentMny(本期发生金额),initMny(期初金额),endMny(期末金额)那么就可以直接用公式来计算期末金额:endMny->currentMny+initMny下面是完整的代码示例:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setExpress(-a->sum(cchmny,cchmny,2*cchmny)-);Stringv2[]=newString[3];v2[0]=-1-;//rowvaluev2[1]=-2-;//rowvaluev2[2]=-3-;Mapmap=newHashMap();map.put(-cchmny-,v2);f.setDataSArray(map);String[]res=f.getValueS();assertEquals(-应该相等!-,-4.0-,res[0]);新一代云ERP解决方案17assertEquals(-应该相等!-,-8.0-,res[1]);assertEquals(-应该相等!-,-12.0-,res[2]);1.8.利用定义函数扩展公式功能你可以在公式中加入自定义函数,为了这个目的,需要做两件事情:1.从nc.vo.pub.expression.function.NcInnerFunction继承自己的函数处理类下面的例子说明了如何编写自己的函数处理类:publicclassMyFunctionextendsNcInnerFunction{publicMyFunction(){numberOfParameters=0;//函数参数的个数}//函数具体的运算,param中是具体的参数publicObjectfunction(Listparam)throwsParseException{if(param==null||param.size()!=0)thrownewParseException(-错误:参数个数不对,mon()不需要参数!-);UFDatedate=newUFDate();returnString.valueOf(date.getMonth());}}可以看出,主要在于编写function()函数,这个函数实现了具体的功能,即如何对传入的参数进行处理。2.在公式执行器中加入自定义函数直接调用addFunction()函数加入你的函数类即可,funname即为你定义函数在公式中的名称。f.addFunction(-funname-,newyourFunctionClass());新一代云ERP解决方案18完成了上述两步工作,你就可以直接在你的公式中使用自定义的函数了!1.9.外接函数的使用本公式解析器支持外接函数6,即可以调用任何一个类中的函数,只要给出公式中函数名,类名,类中函数名,返回参数类型,函数参数类型等,就可以实现在公式中调用外接函数,比如下面的公式就调用了nc.vo.pub.expression.test.Customfunction1类的combineString函数。FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.setSelfMethod(-combine-,//公式中函数名-nc.vo.pub.expression.test.Customfunction1-,//类名-combineString-,//类中函数名ArrayList.class,//返回参数类型newClass[]{String.class,String.class});//函数参数类型f.setExpress(-a->combine(cchmny,\-down\-)-);Listv2=newArrayList();v2.add(-cut-);//rowvaluev2.add(-go-);//rowvaluev2.add(-step-);Mapmap=newHashMap();map.put(-cchmny-,v2);f.setDataSArray(map);String[]res=f.getValueS();assertEquals(-Shouldequal:-,-cutdown-,res[0]);1.10.配置装载自定义函数UAP公式解析模块已经内置了许多常用的函数(参见附录),但是具体在开发应用产品时,这些内置的公式或许并不能完全满足需求,公式解析模块预留了扩展机制,二次开发人员可以根据实际产品或者项目的需要自行添加业务函数。1.8节已经介绍了如何开发自定义函数并通过代码方式注册函数,本小节主要介绍如何通新一代云ERP解决方案19过配置文件的方式注册自定义函数,以获得更好的灵活性。如果希望自定义的公式在所有的公式解析器中都可以使用,则在U8CHOME/resources/formulaconfig/custfunction目录下添加任意文件名的xml注册文件(注意:默认发版盘中此目录下有一个default.xml文件,请不要删除也不要改名),文件格式形如:<?xmlversion=-1.0-encoding=-gb2312-?><formula-array><formula><customType>0</customType><functionName>hzg</functionName><functionClass>nc.vo.function.ivallen</functionClass></formula><formula><customType>0</customType><functionName>hzg2</functionName><functionClass>nc.vo.function.ivallen2</functionClass></formula></formula-array>如果是特定模块的自定义公式,且公式解析器是区分模块构造的,比如:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse(“modulesid”);则可以在上述目录下建立名为模块号的目录,然后将xml文件放到此明细目录中。例如注册仅test模块可以使用的公式,则注册xml文件要放到/resources/formulaconfig/custfunction/modulesid目录下,并且要注意,该目录下一定要保证有一个名为default.xml的文件,所以如果只有一个配置文件,则该文件要命名为default.xml。1.11.运算符重载目前公式解析器支持下列运算符重载:运算符符号相应接口加+IAddOperator:publicObjectadd(Objectobj)减-ISubOperator:Objectsub(Objectobj)新一代云ERP解决方案20乘*IMulOperator:Objectmultiply(Objectobj)除/IDivOperator:Objectdiv(Objectobj)另外如果用户对象要在公式中进行比较运算,请直接实现java.lang.Comparable接口,下面是一个操作符重载的示例:publicclassTestVOimplementsIAddOperator{publicStringname;publicintage;publicTestVO(Stringname,intage){this.name=name;this.age=age;}//运算符重载publicObjectadd(Objectobj)throwsException{TestVOparam2=(TestVO)obj;Stringsname=name+param2.name;intsage=age+param2.age;TestVOres=newTestVO(sname,sage);returnres;}}这样便可以在公式里对TestVO进行加法的运算:FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();f.addVariable(-v3-,newUFDouble(3.0));f.setExpress(-a->vo1+vo2-);Mapmap=initVarMap();f.setDataSArray(map);Object[]res=f.getValueO();assertEquals(-Shouldequal:-,-cch1cch2-,((TestVO)res[0]).name);assertEquals(-Shouldequal:-,48,((TestVO)res[0]).age);新一代云ERP解决方案21其中nitVarMap()函数对vo1和vo2做了初始化:privateMapinitVarMap(){Listv1=newArrayList();v1.add(newTestVO(-cch1-,24));//rowvaluev1.add(newTestVO(-hey1-,25));//rowvaluev1.add(newTestVO(-xuc1-,25));Listv2=newArrayList();v2.add(newTestVO(-cch2-,24));//rowvaluev2.add(newTestVO(-hey2-,25));//rowvaluev2.add(newTestVO(-xuc2-,23));Mapmap=newHashMap();map.put(-vo1-,v1);map.put(-vo2-,v2);returnmap;}1.12.公式简单调试公式解析器通过debug函数,可以实现简单的调试功能,主要为了帮助分析公式每一步运行的情况,确定错误位置。请看下面debug函数用法示例。比如需要调试的公式如下:A->cvn(table,selectfield,wherefield,pkvalue);B->ZeroIfNull(A)*C/10;现在发现B字段就是没有得到值,那么首先就要确认A是否正确的从数据库查询到了值。添加调试语句如下:A->cvn(table,selectfield,wherefield,pkvalue);tempvar->debug(-VariableA=-+A);B->ZeroIfNull(A)*C/10;新一代云ERP解决方案22也可以顺便输出B的值:A->cvn(table,selectfield,wherefield,pkvalue);tempvar->debug(-VariableA=-+A);B->ZeroIfNull(A)*C/10;tempvar->debug(-VariableB=-+B);注意上面的tempvar是一个临时变量,请务必加上且不要和公式变量及模板KEY重复,多个调试语句可以使用同一个临时变量,主要为了防止模板混淆。运行程序执行公式,便会输出调试记录形如:[公式调试]VariableA=45.23[公式调试]VariableB=这样就知道错误大概在什么地方了。1.13.公式使用最佳实践公式技术红皮书1.2节提到过公式的一些基本用法,这里针对U8C使用公式各场景常见的效率问题,总结一些如何更高效使用公式的原则,如果发现目前代码不符合以下提到的原则,请务必修改以达到更好的效率。1.尽可能重用公式解析器实例重新构造一个新的公式解析器实例多少会耗用一些时间,一般来讲大约需要200ms的时间(根据具体机器配置及自定义函数数量不等),所以请避免出现下面这类代码:for(….){//在循环里构造公式解析器实例FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();}…function(…){//频繁调用的方法里反复构造公式解析器实例FormulaParseFatherf=newnc.ui.pub.formulaparse.FormulaParse();}新一代云ERP解决方案23有些代码没有上述列举的这么明显,但是也是殊途同归,最终犯的错误跟上面提到的一样,编码的时候要多多注意,在保证线程安全的情况下,尽量重复使用同一个公式解析器实例。如果在前台,尽量通过成员变量重复使用同一个公式解析器实例,如果没有异步调用,甚至可以考虑使用静态变量保存一个公式解析器实例。如果在后台,则可以考虑使用ThreadLocal来保存一个公式解析器实例,做到线程级共享。可以参考NCFormulaHelper,根据需要构造相应的公式解析器实例。/***取得一个后台线程安全,但是前台不保证线程安全的公式解析器实例,前台如果需要线程*全,请调用:*getThreadSafeFormulaParser()方法.*@returnReturnstheformulaParser.*/publicstaticFormulaParseFathergetFormulaParser()2.尽可能减少公式查询要充分认识到公式查询是一个辅助手段,辅助带出(计算出)一些附加数据(称之为计算属性),不要过多的依靠公式解析,甚至想通过公式解析取代一部分业务代码,这将会导致比较严重的效率问题。有些后台代码,如果可以通过后台关联查询得到相关数据,则不推荐在后台代码里通过公式去查询,感觉走了很多弯路,效率也不会太好。当然类似报表模板这种通用框架,则必须借助模板公式才能达到配置的灵活性,另当别论。推荐对于一些数据量大的业务,数据库可以适当的考虑冗余,比如对于基本档案,管理档案这种相对固定的关联数据,可以考虑在业务单据数据表里同时存储管理档案主键和基本档案主键,避免大量的通过管理档案查询基本档案。3.尽可能批量执行公式公式执行的批量有几个维度:第一就是多个公式批量,建议多个公式一起交给公式解析器执行,我们称之为“列批量”,使用公式解析时,使用如下方法:新一代云ERP解决方案24/***设置需要运算的公式,有了公式解析器实例之后一般调用此方法*@paramnewExpress公式字符串数组*@return设置公式的同时,解析器会做解析,返回值表示所设置的公式是否正确*@seepublicbooleansetExpress(Stringexpr)*/publicbooleansetExpressArray(String[]newExpress)第二就是公式执行要用到的变量,体现在U8C里就是表体里的多行数据,一定要以数组或者列表的方式送到公式执行,我们称之为“行批量”,使用如下方法:/***为公式增加变量,最方便的增加变量的方法,变量可以为简单对象,<br>*也可以为数组或者List<p>*使用方法:<br><code>*Listdeptcode=newArrayList();<br>deptcode.add(-dept003-);<br>f.addVariable(-deptcode-,deptcode);<br></code>*@paramname变量名*@paramvalue变量值支持各种基本类型及数组,List等**/publicvoidaddVariable(Stringname,Objectvalue)第三是前后台调用批量,比如前台执行的多个公式,如果前台缓存不可用,或者公式查询的表、列不在前台缓存范围内,或者因为数据量太大,不能使用前台缓存,此时不能挨个通过远程调用到后台取数,需要批量调用。这种情况需要细分场景,如果是报表类公式,公式里查询的数据量很大,比如存货、客商、供应商,或者跨公司联查,此类数据如果在前台通过公式查询会严重影响缓存LFU算法效果,导致前台缓存数据量急剧增加,影响缓存的稳定性,所以U8C报表类执行公式要求不能前台缓存,则建议使用前台公式后台执行方式,用法如下:新一代云ERP解决方案25Stringformula[]=newString[]{-a->2+3-,-pk_invbasdoc->getColValue(bd_invmandoc,pk_invbasdoc,pk_invmandoc,pk_invmandoc)-,-abctype->getColValue(bd_invmandoc,abctype,pk_invmandoc,pk_invmandoc)-,-checkvalue->getColValue(bd_bdinfo,bdname,pk_bdinfo,\-00010000000000000001\-)-,-code->getColValue(bd_bdinfo,bdcode,pk_bdinfo,\-00010000000000000001\-)-,-invname->getColValue(bd_invbasdoc,invname,pk_invbasdoc,pk_invbasdoc)-,-bbb->getColValue(a,b,c,d)-,-a->invname+\-$$$\-+code-,-invcode->getColValue(bd_invbasdoc,.

1、当您付费下载文档后,您只拥有了使用权限,并不意味着购买了版权,文档只能用于自身使用,不得用于其他商业用途(如 [转卖]进行直接盈利或[编辑后售卖]进行间接盈利)。
2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。
3、如文档内容存在违规,或者侵犯商业秘密、侵犯著作权等,请点击“违规举报”。

碎片内容

U8Cloud开发课件-红皮书-U8 cloud V1.0-公式技术红皮书.pdf

确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息
QQ群
  • 答案:my7c点击这里加入QQ群
支持邮箱
微信
  • 微信