集成JasperReport与BerkeleyDB

JasperReport是一个流行的Java开源报表工具,BerkeleyDB是一个流行的开源嵌入式数据库产品. 长久以来,JasperReport无法显示BerkeleyDB中的数据. 但是,现在这一状况得到了改善.JasperForge在2008-08-05正式发布了BerkeleyDB的Driver,这意味着,以后可以使用 JasperReport来显示存储于BerkeleyDB中的内容了.

本文将主要介绍如何利用JasperReport来显示 BerkeleyDB的数据.BerkeleyDB分为三个类别,Core Edition, Java Edition,和XML Edition. 其中Core Edition使用最为广泛,故而,本文针对的是Core Edition最新的Release, 4.7.25. 为了给读者一个直观的印象.本文将创建一个使用BerkeleyDB用于存储学生信息的数据库,而后使用JasperReport显示其内容.

1 下载并安装/编译BerkeleyDB,下载地址为
  http://www.oracle.com/technology/software/products/berkeley-db/db/index.html
  可以选择下载.msi或者压缩文件,如果下载的是压缩文件,需要自己来编译.BerkeleyDB提供了针对Linux的configure/make和针对windows的.sln和.dsw文件,编译方法不在此累述.
需要注意的是,本处需要java的支持,故而,需要编译java的库. 对于configure/make而言,在configure的时候需要--enable-java,用.sln/.dsw的则需要编译Project db_java.

2 创建Student数据库,本处只给出C代码的片段.
static char *env_home="D:/tmp/jasper-env";
/* This is the struct for student */
typedef struct student {
    char student_no[20]; /* student no. */
    char student_name[20]; /* student name */
    char sexuality[8]; /* sex */
    int sex_code;  /* code for sex male as one, female as two, and 0 stands for unknown.*/
    char class_no[20]; /* class no. */
    char class_name[100]; /* class name */
    char brief_class_name[60]; /* brief class name */
    char major_name[100]; /* major name */
    char register_daymonth[20]; /* the year and month for entering */
    char nationality[50]; /* nationality */
    char birthday[20]; /* the year and month for birthday */
    char id_no[30]; /* ID card no. */
}STUDENT;
static char *student_data_infile="D:/tmp/stu/student.data.out";
static char *student_db_name="student.db";

int create_db_of_student(int argc, char *argv[]){
    DB_ENV *dbep;
    DB *dbp;
    STUDENT stu;
    DBT dbt_key,dbt_data;
    char buff[500];
    int len=0;
    FILE *srcfp=NULL;
    char *lineptr=NULL;
    int intval=0;
    int ret=0;
    u_int32_t envoflag=DB_CREATE|DB_RECOVER|DB_INIT_TXN|DB_INIT_MPOOL|DB_INIT_LOCK|DB_INIT_LOG;

    ret=db_env_create(&dbep,0);
    ret=dbep->remove(dbep,env_home,DB_FORCE);
    ret=db_env_create(&dbep,0);
    ret=dbep->open(dbep,env_home,envoflag,0);
    ret=db_create(&dbp,dbep,0);
    ret=dbp->remove(dbp,student_db_name,NULL,0);
    ret=db_create(&dbp,dbep,0);
    ret=dbp->open(dbp,NULL,student_db_name,NULL,DB_BTREE,DB_CREATE,0);

    srcfp=fopen(student_data_infile,"r");

    while(1){
   
        /*field student_no*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.student_no,0,sizeof(stu.student_no));
        sprintf(stu.student_no,"%s",buff);

        /*field student_name*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.student_name,0,sizeof(stu.student_name));
        sprintf(stu.student_name,"%s",buff);

        /*field sexuality*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.sexuality,0,sizeof(stu.sexuality));
        sprintf(stu.sexuality,"%s",buff);

        /*field sex_code*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(&stu.sex_code,0,sizeof(stu.sex_code));
        intval=atoi(buff);
        if(errno==ERANGE)
            intval=1;
        stu.sex_code=intval;

        /*field class_no*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.class_no,0,sizeof(stu.class_no));
        sprintf(stu.class_no,"%s",buff);

        /*field class_name*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.class_name,0,sizeof(stu.class_name));
        sprintf(stu.class_name,"%s",buff);

        /*field brief_class_name*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.brief_class_name,0,sizeof(stu.brief_class_name));
        sprintf(stu.brief_class_name,"%s",buff);

        /*field major_name*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.major_name,0,sizeof(stu.major_name));
        sprintf(stu.major_name,"%s",buff);

        /*field register_daymonth*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.register_daymonth,0,sizeof(stu.register_daymonth));
        sprintf(stu.register_daymonth,"%s",buff);

        /*field nationality*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.nationality,0,sizeof(stu.nationality));
        sprintf(stu.nationality,"%s",buff);

        /*field birthday*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.birthday,0,sizeof(stu.birthday));
        sprintf(stu.birthday,"%s",buff);

        /*field id_no*/
        lineptr=fgets(buff,500,srcfp);
        if(lineptr==NULL)
            break ;
        if(buff[strlen(lineptr)-1]=='/n')
            buff[strlen(lineptr)-1]='/0';
        memset(stu.id_no,0,sizeof(stu.id_no));
        sprintf(stu.id_no,"%s",buff);

        memset(&dbt_key,0,sizeof(DBT));
        memset(&dbt_data,0,sizeof(DBT));
        dbt_key.data=stu.student_no;
        dbt_key.size=(u_int32_t)(strlen(stu.student_no)+1);
        dbt_data.data=&stu;
        dbt_data.size=sizeof(STUDENT);
       
        ret=dbp->put(dbp,NULL,&dbt_key,&dbt_data,DB_NOOVERWRITE);
        if(ret)
            dbp->errx(dbp,"%s/n",db_strerror(ret));
    }

        fclose(srcfp);
        ret=dbp->close(dbp,0);
        ret=dbep->close(dbep,0);
        return ret;
}

3 编写对应的Java绑定类. 为了让JasperReport显示一个BerkeleyDB的数据库中的内容,需要为该数据库的key和data编写绑定类(Binding Class)以及JavaBeans. JavaBeans代表key或data中在java的数据如何表示,BindingClass则用来指示如何用key/data的字节数组来产生对应的 JavaBeans. BindingClass应当继承com.sleepycat.bind.tuple.TupleBinding,并且重新定义其 entryToObject和objectToEntry的方法.entryToObject将字节数组转化为对象,objectToEntry将对象转 化为字节数组.由于本处只需要前者,故而只给出entryToObject方法的一个实现.

技术上而言, BindingClass的编写者,应当对BerkeleyDB如何数据的字节表示相当清楚,比如某段信息在几个字节长度,或者某段信息以什么字符作为边界字符等等.如此,才能将字节解析出来,并且转化为JavaBean.

在编写bindingClass的时候, 需要考虑几个因素:
a 系统的endian,endian决定了解析整数的方式,一般的系统都是little-endian,而java虚拟机是big-endian,如果endian不一样, 就不能使用TupleInput的函数来获得整数,需要自己逐自己处理以产生整数.

b 字符串的解析:C中字符串以'/0'结束,而Java中是以0XFF结尾,故而不能直接用TupleInput的readString来获得字符串,而new String()将会处理所有提供的长度,而不会到'/0'就停止,故而最好自己获得'/0'的位置.

c 对齐.对齐对结构体内部的成员地址有要求,故而,源代码定义的结构体,并非与编译期的结构体完全一致.编译器会在某些字段与字段之间加入padding字 符,以满足对其要求.此情况下,应当分析该编译器的对齐要求,并且分析编译期的实际结构体是什么样的,这样才能够解析字节数组.

Student Key的JavaBean:
public class StudentKey {
    private String student_no;
  .....构造函数,set/get函数省略....
}

Student Key的绑定类:
public class StudentKeyBinding extends TupleBinding {
    public Object entryToObject(TupleInput arg0) {
        byte[] bytes=arg0.getBufferBytes();
        String student_no=new String(bytes, 0,bytes.length-1);  //20
        StudentKey stuKey=new StudentKey(student_no);
        return stuKey;       
    }
  ......objectToEntry略......
}

Student data的JavaBean:
public class StudentData{ 
    private String student_no;
    private String student_name;
    private String sexuality;
    private int sex_code;
    private String class_no;
    private String class_name;
    private String brief_class_name;
    private String major_name;
    private String register_daymonth;
    private String nationality;
    private String birthday;
    private String id_no;
  .....构造函数,set/get函数省略....
 }

Student Data的绑定类:
public class StudentDataBinding extends TupleBinding {
    public Object entryToObject(TupleInput arg0) {
        byte[] bytes=arg0.getBufferBytes();
        byte[] newbytes=null;
        //student_no  20
        int loc1=0;
        int len1=20;   
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String student_no=new String(newbytes, 0,newbytes.length-1);

        //student_name 20
        loc1+=len1;
        len1=20;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String student_name=new String(newbytes, 0,newbytes.length-1);

        //sexuality 8
        loc1+=len1;
        len1=8;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String sexuality=new String(newbytes, 0,newbytes.length-1);

        //sex_code 4
        loc1+=len1;
        len1=4;
        int sex_code=IntTools.getIntFromBytes(bytes,loc1,len1);

        //class_no 20
        loc1+=len1;
        len1=20;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String class_no=new String(newbytes, 0,newbytes.length-1);

        //class_name 100
        loc1+=len1;
        len1=100;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String class_name=new String(newbytes, 0,newbytes.length-1);

        //brief_class_name 60
        loc1+=len1;
        len1=60;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String brief_class_name=new String(newbytes, 0,newbytes.length-1);

        //major_name 100
        loc1+=len1;
        len1=100;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String major_name=new String(newbytes, 0,newbytes.length-1);

        //register_daymonth 20
        loc1+=len1;
        len1=20;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String register_daymonth=new String(newbytes, 0,newbytes.length-1);

        //nationality 50
        loc1+=len1;
        len1=50;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String nationality=new String(newbytes, 0,newbytes.length-1);

        //birthday 20
        loc1+=len1;
        len1=20;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String birthday=new String(newbytes, 0,newbytes.length-1);

        //id_no 30
        loc1+=len1;
        len1=30;
        newbytes=ByteTools.getEndedBytesByBorder(bytes,loc1, (byte)0);
        String id_no=new String(newbytes, 0,newbytes.length-1);
       
        StudentData stu=new StudentData(student_no, student_name, sexuality, sex_code, class_no, class_name, brief_class_name,
                  major_name, register_daymonth, nationality, birthday, id_no);
        return stu;
    }
  ......objectToEntry略......
}

在完成java类的编写(以上是StudentKey,StudentKeyBinding,StudentData,StudentDataBinding)之后,可以把这些类打包到一个jar中,本处打包为stu.jar.

4 安装JasperReport的BerkeleyDB Driver,并且建立BerkeleyDB的连接.
 a 下载并安装IReport, http://jasperforge.org/plugins/project/project_home.php?group_id=83
 b 下载Berkeley DB Driver, http://jasperforge.org/plugins/esp_frs/?group_id=170,并且解压,假设其目录为bdbdriver.
 c 将bdbdriver/lib下的jasperreports-bdb-<version>.jar复制到Ireport的lib目录下,将 bdbdriver/lib下的db-<version>.jar复制到Ireport的lib目录下
 d 将BerkeleyDB的库文件的位置加入到IReport的启动脚本中,对于windows而言,这个启动脚本是startup.bat,所以需要在Ireport guiMainFrame启动参数中加入类似于底下的内容:
-Djava.library.path="D:/projects/BDB_build/db/build_windows_Release/Release", 同时还应当保证该目录在系统环境变量PATH之中,比如可以在启动guiMainFrame前加入以下行:
set PATH=D:/projects/BDB_build/db/build_windows;%PATH%
或者编辑系统的环境变量,加入该路径.
 e 将stu.jar拷贝到Ireport的lib目录下.
 f 建立BerkeleyDB的连接,打开IReport, 到"Data->Connections/Data Sources",单击"New",选择类型为:"Oracle Berkeley DB Connection"后单击"Next",将可以看到以下图:

填入环境目录,选择使用Base API,填入class_catalog. Class_catalog只是对用java api创建的数据库才有真实的作用,但是,当前,这个对c api创建的数据库也必要. 可以创建一个空的class_catalog,具体做法就是在环境目录中创建一个StoredClassCatalog的数据库,但是不写入任何数据,如 下:
            String catalogDBName="class_catalog";       
            DatabaseConfig catalogConf=new DatabaseConfig();
            catalogConf.setAllowCreate(true);
            catalogConf.setType(DatabaseType.BTREE);
            catalogDB=env.openDatabase(null, catalogDBName, null, catalogConf);
            StoredClassCatalog storedCatalog=new StoredClassCatalog(catalogDB);
            storedCatalog.close();
在下一个版本中,class_catalog对C API创建的数据库将不再必要.
单击Test,如果成功,则会提示成功:

创建成功后,选择此数据库连接为活跃连接(Active Connection)

5 创建报表来显示数据.
a 新建一个报表,而后单击"Data->Report Query",选择Query Language为bdb,而后输入Bdb的查询表达式.BDB查询表达式的基本格式为:
PrimaryDatabaseName,keyClass,keyBinding,valueClass,valueBinding
所以按照此格式,本处输入以下表达式:


而后,可用的字段就显示出来了,这些字段就是在JavaBean中的get/set 字段.

b 制作报表,并且执行报表,具体操作方法略.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值