首先非常感谢老刀研发的CellReport解决了中小企业报表难的问题。
CellReport的官网地址:https://gitee.com/NoneDay/CellReport 欢迎小伙伴围观;对应的文档地址:http://noneday.gitee.io/cellreport/
CellReport强大的功能,不用我在这里赘述。用过的人都知道。
本文主要记录一下CellReport的脚本功能。
一直以来,都希望有一款趁手的脚本解析和执行器来满足自定义脚本功能,满足不同场景、不同功能的需求。
一个美好的周末,主动联系了一下CellReport的作者(老刀),在老刀热心的指点,不厌其烦的解答后,终于满足了我的小心愿。
言归正传,实现脚本功能的步骤如下:
- 创建.NET6的项目,并引入CellReport.dll和Antlr3.Runtime.dll;
- 单独表达式例子:创建ExprFaced2实例,并将参数传入calculate方法中;具体代码如下:
1 public static bool RunExpress(string express, out IDictionary<Object, Object> resDic) 2 { 3 bool ok = false; 4 resDic = new Dictionary<Object, Object>(); 5 try 6 { 7 var ef = new ExprFaced2(); 8 ef.addNewScopeForScript(); 9 var _env = new Env(); 10 //固定要加的,脚本运行环境使用环境变量的时候,要找这个变量 11 ef.addVariable("__env__", _env); 12 // 可以直接测试加法 13 //var tt = exprFaced.calculate("=1+2+4 "); 14 //var tt2 = exprFaced.calculate("=iif(11>2,true,false)"); 15 var exec_result = ef.calculate($"{express} ;"); 16 if (exec_result is Exception ex) 17 { 18 ok = false; 19 throw ex; 20 } 21 resDic = exec_result as IDictionary<Object, Object>; 22 ok = true; 23 } 24 catch (Exception ex) 25 { 26 string err = ex.Message; 27 throw; 28 } 29 return ok; 30 }
- 脚本例子,同上面不同的地方,我们需要事先定义好执行的脚本,然后再传入脚本对应的参数;
js脚本定义,本脚本定义了两个函数,其中main作为主函数,login_script做为子函数执行对应的业务逻辑
1 function login_script(userid, password) { 2 var _password = password + '-----' 3 return { errcode: 0, message: _password } 4 } 5 function main(userid, password) { 6 return login_script(userid, password) 7 }
封装执行脚本RunScript方法,其中script为脚本内容;varDic为参数字典用户传递参数,并拼接主函数入口的参数个数;resDic为返回的结果字典;expFun为主函数入口;data_source为同数据库交互是指定的数据源(数据源名称、数据源连接串、数据库类型)
1 public static bool RunScript(string script, Dictionary<string, object> varDic, out IDictionary<Object, Object> resDic, string expFun = "main", DbSource data_source = null) 2 { 3 bool ok = false; 4 resDic = new Dictionary<Object, Object>(); 5 try 6 { 7 var exprFaced = new ExprFaced2(); 8 //addNewScopreForScipt是为了载入脚本的。里面的函数仅仅是被解析了,没有被执行 9 exprFaced.addNewScopeForScript(script); 10 var __env__ = new Env(); 11 // 如果需要数据库连接,则在此定义数据源 12 if (data_source != null) 13 { 16 __env__.addDataSource(data_source.Name, data_source.ConnString, data_source.DbType, "0"); 17 } 18 //固定要加的,脚本运行环境使用环境变量的时候,要找这个变量 19 exprFaced.addVariable("env", __env__); 20 exprFaced.addVariable("__env__", __env__); 21 exprFaced.addVariable("_user_", null); 22 string funParams = string.Empty; 23 //加自己的预定义变量 24 if (varDic != null && varDic.Count > 0) 25 { 26 foreach (var kv in varDic) 27 { 28 exprFaced.addVariable(kv.Key, kv.Value); 29 } 30 funParams = string.Join(",", varDic.Keys).ToString(); 31 } 42 var exec_result = exprFaced.calculate("{ " + $"{expFun}({funParams});" + "\n}", new()); 44 if (exec_result is Exception ex) 45 { 46 ok = false; 47 throw ex; 48 } 49 resDic = exec_result as IDictionary<Object, Object>; 50 ok = true; 51 } 52 catch (Exception ex) 53 { 54 string err = ex.Message; 55 throw; 56 } 57 return ok; 58 }
调用方法(非数据库交互的,不需要传递data_source):
1 string test_user = "admin"; 2 string test_password = Guid.NewGuid().ToString(); 3 Dictionary<string, object> varDic = new Dictionary<string, object>(); 4 varDic.Add("userid", test_user); 5 varDic.Add("password", test_password); 6 IDictionary<Object, Object> resDic = new Dictionary<Object, Object>(); 7 var ok = ScriptRun.RunScript(script, varDic, out resDic);
调用成功我们就可以通过resDic获取对应的结果了。
- 同数据交互的脚本
- 首先要在Startup.cs中注册数据库对应的dll
- 如果用到kata,还需要注册Func_kata对应的执行函数;
具体看代码,我这里是winform应用,不过方式一样,没有区别
1 public static void Main(string[] args) 2 { 3 try 4 { 5 //DbProviderFactories.RegisterFactory("MySql", MySqlClientFactory.Instance); 6 //DbProviderFactories.RegisterFactory("Microsoft.Data.Sqlite", SqliteFactory.Instance);
//此处的名称需要根据CellReportweb端中定义数据源时下拉框保持一致 7 DbProviderFactories.RegisterFactory("SqlClient", SqlClientFactory.Instance);
//如果需要用到kata脚本的时候才需要调用 8 CreatHostBuilder(args).Build(); 9 ApplicationConfiguration.Initialize(); 10 Application.Run(new Form1()); 11 } 12 catch (Exception) 13 { 14 throw; 15 } 16 } 17 public static IHostBuilder CreatHostBuilder(string[] args) => 18 Host.CreateDefaultBuilder(args) 19 .ConfigureServices((hostContext, services) => 20 { 21 CellReport.core.expr.ExprHelper.buildFuncMap(); 22 //CellReport.core.expr.ExprHelper.AddFunc(typeof(CellReport.function.Func_md5)); 23 //CellReport.core.expr.ExprHelper.AddFunc(typeof(CellReport.function.Func_qr_code)); 24 CellReport.core.expr.ExprHelper.AddFunc(typeof(CellReport.function.Func_kata)); 25 CellReport.core.expr.ExprHelper.AddFunc(typeof(CellReport.function.Func_kata_Variable)); 26 });
1 function main(dataSource, tableName, fieldNames) { 2 var db = openDb(`${dataSource}`) 3 var data = null 4 if (fieldNames == null || fieldNames == '') 5 data = db.select(`select * from ${tableName} ;`) 6 else 7 data = db.select(`select ${fieldNames} from ${tableName} ;`) 8 db.close() 9 return { data } 10 }
1 Dictionary<string, object> varDic = new Dictionary<string, object>(); 2 varDic.Add("dataSource", SQL.Name); 3 varDic.Add("tableName", "iot_device"); 4 varDic.Add("fieldNames", null); 5 IDictionary<Object, Object> resDic = new Dictionary<Object, Object>(); 6 var ok = ScriptRun.RunScript(script, varDic, out resDic, "main", SQL);
SQL为DataSource,具体定义为:
DbSource SQL = new DbSource { Name = "KIT", DbType = "SqlClient", ConnString = "Data Source=127.0.0.1;Initial Catalog=xx;Persist Security Info=True;User ID=sa;Password=xxx;Min Pool Size=1;Max Pool Size=50;Connect Timeout=15000;" };
- kata脚本如下:,调用函数和方法同上面保持一致
1 function main(dataSource, tableName, fieldNames) { 2 var db = kata(`${dataSource}`) 3 var data = db 4 .Query('iot_device') 5 .Get() 6 .select((x) => { 7 return { id: x.id, device_name: x.device_name } 8 }) 9 return { data } 10 }
注意事项:
- 对应依赖的dll的版本同CellReport例子中保持一致;
- 脚本的语法同js语法,变量定义var,每个语句必须要分号结束;具体的语法参考对应的文档:http://noneday.gitee.io/CellReport/zh/guide/lang.html#基础数据类型
- 在使用数据库功能时,需要增加其他的几个dll,包括:
1 <Reference Include="CellReport"> 2 <HintPath>.\libs\CellReport.dll</HintPath> 3 </Reference> 4 <Reference Include="Antlr3.Runtime"> 5 <HintPath>.\libs\Antlr3.Runtime.dll</HintPath> 6 </Reference> 7 <Reference Include="MySql.Data"> 8 <HintPath>.\libs\MySql.Data.dll</HintPath> 9 </Reference> 10 <Reference Include="Microsoft.Data.Sqlite"> 11 <HintPath>.\libs\Microsoft.Data.Sqlite.dll</HintPath> 12 </Reference> 13 <Reference Include="SqlKata"> 14 <HintPath>.\libs\SqlKata.dll</HintPath> 15 </Reference> 16 <Reference Include="SqlKata.Execution"> 17 <HintPath>.\libs\SqlKata.Execution.dll</HintPath> 18 </Reference> 19 <Reference Include="Dapper"> 20 <HintPath>.\libs\Dapper.dll</HintPath> 21 </Reference> 22 <Reference Include="Humanizer"> 23 <HintPath>.\libs\Humanizer.dll</HintPath> 24 </Reference>
标签:脚本,功能,varDic,dll,CellReport,var,new,data From: https://www.cnblogs.com/egreen/p/16976498.html