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 制作报表,并且执行报表,具体操作方法略.
本文将主要介绍如何利用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 制作报表,并且执行报表,具体操作方法略.