Java 如何调用 SPL 脚本

【摘要】

集算器提供了 JDBC 驱动,很容易嵌入到 Java 程序调用,方法和在 Java 中执行 SQL 和存储过程类似。
去乾学院看个究竟:Java 如何调用 SPL 脚本

Java 应用程序中部署集算器 JDBC

首先将 JDBC 部署到 java 应用项目中,简单来说就是,将启动 JAVA 应用程序时加载集算器所需的 jar 包及配置文件放到项目中。需要注意的是,集算器 JDBC 所要求的 JDK 版本不得低于 1.6。

1. 加载驱动 jar

集算器 JDBC 类似一个不带物理表的数据库 JDBC 驱动,可以把它简单的看成是一个只有存储过程的数据库。另外,集算器 JDBC 是个完全嵌入式计算引擎,已经在 JDBC 中完成了所有运算,不象数据库那样 JDBC 只是个接口,实际运算在独立的数据库服务器完成。

如果在 web 应用项目下,可以把这些 jar 包放在 WEB-INF/lib 目录下。集算器 JDBC 需要三个基础 jar 包,都可以在 [安装目录]\esProc\lib 目录下找到:

dm.jar  //集算器计算引擎及JDBC驱动包
icu4j_3_4_5.jar  //处理国际化 
jdom.jar  //解析配置文件

除了以上的必需 jar,还有一些为完成特定功能的 jar 包:
比如数据库作为数据源,那么还需要相应数据库的驱动 jar 包;
要读写 Office 文件,则需要加入 poi*.jar 和 xmlbeans.jar;
要使用绘制图形功能,则需要加入 SVG 图形处理相关的 jar 包,包括 batik*.jar、js.jar、pdf-transcoder.jar、xalan-2.6.0.jar、xercesImpl.jar、xml-apis.jar、xml-apis-ext.jar。

2. 部署 raqsoftConfig.xml

集算器还有个重要的配置文件 raqsoftConfig.xml,可以在 [安装目录]\esProc\config 下找到,需复制后放置在应用项目的类路径下,配置文件的名称不可改变。
在 raqsoftConfig.xml 文件中,配置了授权信息、集算器主路径、dfx 文件寻址路径等各类信息。我们先看下最基本的配置,即集算器授权文件配置:

<?xml version="1.0" encoding=" UTF-8"?>
< Config Version="2">
 <Runtime>
 <Esproc>
    <!--集算器授权文件配置,可以是绝对路径,也可以是相对路径,使用相对路径时是相对于类路径-->
    <license>esproc.xml</license>
    <!--试用授权文件可从润乾公司官网中下载-->
 </Esproc>
 </Runtime>
</Config>

Java 调用

Java 程序中调用 SPL 脚本 ,与 java 中调用 SQL 和存储过程类似,下面来看下具体是怎样实现的:

执行 SPL 语句

比如创建一个数据表,并添加两个字段 baseNum、square2,分别将 100 以内的自然数及其的平方值组成 100 条记录插入到数据表中,最后将表中的数据作为结果集返回。

Java 代码如下:

 public  void runSPL() throws ClassNotFoundException, SQLException{
        Connection con = null;
        PreparedStatement st;
        ResultSet set ;
    //建立连接
    Class._forName_("com.esproc.jdbc.InternalDriver");
    con= DriverManager._getConnection_("jdbc:esproc:local://");
    //直接执行SPL语句,返回结果集
    st = (PreparedStatement)con.createStatement();
    ResultSet rs = st.executeQuery("=100.new(~:baseNum,~*~:square2)");
    //简单处理结果集,将结果集中的字段名与数据输出 
      ResultSetMetaData rsmd = rs.getMetaData();
      int colCount = rsmd.getColumnCount();
    for ( int  c = 1; c <= colCount;c++) {
    String title = rsmd.getColumnName(c);
    if( c > 1 ) {
        System._out_.print("\t");
    }
    else {
        System._out_.print("\n");
    }
        System._out_.print(title);
  }
    while (rs.next()) {
     for(int c = 1; c<= colCount; c++) {
       if ( c > 1 ) {
            System._out_.print("\t");
  }
       else {
            System._out_.print("\n");
  }
     Object o = rs.getObject(c);
     System._out_.print(o_.toString());
  }
  }
   //关闭连接
   if (con!=null) {
        con.close();
   }

执行结果:

imagepng

在 SPL 中访问本地文件

通过 SPL 还可以访问本地的文件,其中包括 Txt、Excel、Json、Csv、Ctx 等多种类型的文件,访问时可以通过绝对路径查文件位置,也可以通过相对路径查找,使用相对路径时,则是相对于配置文件中的主目录,所以,首先我们来配置下主目录:
在 raqsoftConfig.xml 文件的节点 < Esproc ></ Esproc > 中添加以下节点:

 <!--集算器主路径,该路径为单一的绝对路径-->
 <mainPath>D:\mainFile</mainPath>

我们把要调用的文件 employee.txt 放到主目录下面,在 JAVA 中调用时,建立连接、输出结果等部分的代码与上例是完全相同的,调用 SPL 语句部分如下:

ResultSet rs=st.executeQuery("=file(\"D:\mainFile\employee.txt\").import@t()");

这里支持绝对路径与相对路径的使用,在 Java 中使用反斜杠 \ 表示转义符。

执行结果:

imagepng

对于这种简单运算,还可以使用简单 SQL 语法:

ResultSet rs=st.executeQuery("$()select * from employee.txt");

其中 $() 表示访问本地文件系统,两种写法的结果集相同。

带参数的 SPL 语句

参数是 SQL 语句的一个重要组成部分,同样,SPL 语句中也支持参数的使用,例如,像上例中,要查询 employee.txt 文件中的数据,但是要求只查询工资在 12000 到 20000 之间的记录,并根据工资升序排序:

调用部分代码如下:

 PreparedStatement pst = con.prepareStatement("$()select * from employee.txt where SALARY > ? and SALARY< ? order by SALARY");
 //设置参数
 pst.setObject(1,12000);
 pst.setObject(2,20000);
 ResultSet rs = pst.executeQuery();

其中用?表示参数,然后通过 setObject() 为上面的参数一一赋值。

执行结果:

imagepng

有数据源的 SPL 语句

集算器 JDBC 既然是个数据计算引擎,那么数据来源的重要途径之一就是数据库了,JAVA 中如何来调用带数据源的 SPL 语句呢?往下看:
JAVA 调用带数据源的 SPL 语句之前,需要先在应用项目中添加对应的数据库驱动,然后在配置文件 raqsoftConfig.xml 中配置数据源信息。
例如:调用的 SPL 语句中使用的数据源名称为 demo,数据库类型为 HSQL,那么配置如下:
首先,将 HSQL 的数据集驱动 hsqldb.jar 加载到应用项目中;
其次,在 raqsoftConfig.Xml 的 < Runtime ></ Runtime > 节点中配置数据源信息:

<DBList>
<DB name="demo"> <!--数据源名称-->
<property name="url" value="jdbc:hsqldb:hsql://127.0.0.1/demo" /> <!-- url连接-->
<property name="driver" value="org.hsqldb.jdbcDriver" /> <!--数据库驱动-->
<property name="type" value="13" /> <!--数据库类型-->
<property name="user" value="sa" /> <!--用户名-->
<property name="password" value=""/> <!--密码-->
<property name="batchSize" value="1000" />
<property name="autoConnect" value="true" /><!--是否自动连接,如果设定为true,则可以直接以$开头的SQL语句来访问数据库,如果为false,则不会自动连接,使用前必须用connect(db)语句创建数据库连接-->
<property name="useSchema" value="false" />
<property name="addTilde" value="false" />
<property name="dbCharset" value="UTF-8" />
<property name="clientCharset" value="UTF-8" />
<property name="needTransContent" value="false" />
<property name="needTransSentence" value="false" />
<property name="caseSentence" value="false" />
</DB>
</DBList>

现在我们通过 SPL 从 demo 数据源中查询 SALES 表,过滤出 SELLERID 为 3 的员工,在 2014 年 11 月 11 号到 2014 年 12 月 12 号期间的所有订单信息:

调用部分代码如下:

  PreparedStatement pst = con.prepareStatement("$(demo)select * from SALES  where  SELLERID = ? and  ORDERDATE>? and ORDERDATE<?");
 //设置参数
 pst.setObject(1,"3");
 pst.setObject(2,java.sql.Date.valueOf("2014-11-11"));
 pst.setObject(3,java.sql.Date.valueOf("2014-12-12"));
 //获取结果集
 ResultSet rs = pst.executeQuery();

结果集输出如下:

imagepng

执行 SPL 脚本

JAVA 集成集算器 JDBC 后,除了可以直接执行单句的 SPL 语句,还可以调用更复杂的 SPL 脚本(后缀为 dfx 的文件)。
比如下面的 dfx 文件:



A

B

C

1

=demo.query("select NAME as CITY, STATEID as STATE from   CITIES")

[]


2

for A1

=demo.query("select * from STATES where   STATEID=?",A2.STATE)


3


if left(B2.ABBR,1)==arg1

>A2.STATE=B2.NAME

4



>B1=B1|A2

5

return B1




SPL 脚本思路:
循环遍历 CITIES 表记录,通过 CITIES. STATES 过滤 STATES 表,若 STATES. ABBR 首字母为参数 arg1,则将 STATES 表中的 NAME 值赋给 CITIES. STATE,并将 CITIES 表中的这条记录拼接到 B1 格中,最终返回 B1 格的结果集。
在这个网格文件中,需要从数据源 demo 中获取数据,同时使用了参数 arg1:

imagepng

数据源配置方法可以参考上面的示例,网格文件保存为 city.dfx,dfx 文件可以存放在应用项目类路径或 raqsoftConfig.xml 中配置的主目录下,当 dfx 文件比较多的时候,为了便于统一维护和管理,我们还可以将 dfx 文件放到 dfx 寻址路径中,寻址路径的配置方式如下:
在 raqsoftConfig.xml 文件的 < Esproc></ Esproc> 节点中,添加以下内容:

<dfxPathList>
   <!--配置dfx文件寻址路径,该路径为绝对路径,可以设置多个路径,以“;”隔开-->  
   <dfxPath>D:\dfxFile</dfxPath>
</dfxPathList>

调用部分代码如下:

  //通过call调用存储过程,其中city是dfx的文件名,?表示参数,多个参数间用逗号间隔
  st =con.prepareCall("call city(?)");
  st.setObject(1, "A");
  //获取结果集
  ResultSet rs = st.executeQuery();

通过 call 调用 dfx 文件除了上面的写法,还可以在调用 dfx 时直接传参,如下:

  st=con.prepareStatement("call city(\"A\")");
  //获取结果集
  ResultSet rs = st.executeQuery();

执行结果:

imagepng

在 Java 中调用 dfx 文件时,也可以省略 call 直接使用 dfx (…),该用法同样有两种写法,如下:

  //dfx名称与参数间以空格作为分隔,多个参数间通过逗号分隔
  st =con.prepareCall("city ?");
  //设置参数
  st.setObject(1,"A");

或:

 st =con.prepareCall("city \"A\"");

以上几种调用方法最终获取的结果集均相同。
上述内容就是 Java 调用 SPL 脚本的常用方式了,想了解更多用法的小伙伴儿可以去官网上的在线教程中查看