将集智平台报表sql和参数输出到xml文件中

需求背景

客户要求能够将报表名称、报表数据集sql、报表参数值、访问报表时间、登录人信息等信息输出到xml文件中,以对该xml文件进行分析

要求:1sql是完整的sql语句,即可以直接拿到数据库端执行。 2、文件需进行大小控制,可分时间段存储xml

实现思路

鉴于最终的参数值可以在报表计算后取到,该需求可以通过报表计算监听类实现。所有信息可以通过dom4j写入xml文件。

难点在于我们直接获取的数据集sql是带有问号的原始sql,需要将指定位置的问号替换成对应的参数值,替换的时候要考虑到类型转换。

程序介绍

先准备带有参数模板的报表,在发布报表的jsp中指定计算监听类,如:calculateListener=”listener.CalcListenerWriteSql2″

CalcListenerWriteSql2.java介绍:

1、 public void beforeCalculate()

计算监听类计算后方法,首先初始化一个map,用于存储数据集名和数据集sql(完整不带问号的sql)。

Map<String, String> dsMap = newHashMap<String, String>();// 初始化存放数据集名,数据sqlmap

再在该方法中获取数据集元对象以及数据集个数,通过循环数据集个数获取数据集名和通过getDsSql()方法获取数据集sql

DataSetMetaData dsmd = report.getDataSetMetaData(); // 获取数据集元对象

intdsNum = dsmd.getDataSetConfigCount(); // 获取数据集个数

最后map及必要信息传给操作xml的方法,本例中xml文件都是以当前年月命名,若无该该文件则创建,否则修改,以达到每月创建使用一个xml的目的。

createXML(dsMap,raqName,userID,now,currYM);//创建xml

modifyXML(dsMap,raqName,userID,now,currYM);//修改xml

2、 public String getDsSql(SQLDataSetConfig sdsc)

根据传递过来的SQLDataSetConfig对象获取对应数据集sql(原始sql,带问号的),该方法通过getParam()sql中问号与参数值对应,最后返回一个完整的sql字符串。

3、 public Map<Integer,String> getParam(SQLDataSetConfig sdsc)

本方法先判断报表数据集的参数类型,经Expression计算参数表达式值,最后将参数位置和参数值存到map中返回。

Expression exp = newExpression(context, paramExp);

Object afterCalcObj = exp.calculate(context, false);

4、 publicvoidcreateXML(Map<String,String> map,String raqName,String userID,String now,String currYM)

创建xml方法(本例使用dom4j操作xml,使用时需导入dom4j的包)。其中创建时需考虑到xml文件编码、汉字乱码以及特殊符号转码等问题。

5、 publicvoidmodifyXML(Map<String,String> map,String raqName,String userID,String now,String currYM)

修改xml方法。实现类似创建,注意同4

Java程序源码:

packagelistener;

importjava.sql.Date;

importjava.sql.Time;

importjava.text.DateFormat;

importjava.text.SimpleDateFormat;

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.Iterator;

importjava.util.Map;

importjava.io.File;

importjava.io.FileOutputStream;

importjava.io.IOException;

importjava.math.*;

importorg.dom4j.Document;

importorg.dom4j.DocumentException;

importorg.dom4j.DocumentHelper;

importorg.dom4j.Element;

importorg.dom4j.io.OutputFormat;

importorg.dom4j.io.SAXReader;

importorg.dom4j.io.XMLWriter;

importcom.runqian.report4.model.expression.Expression;

importcom.runqian.report4.usermodel.AbstractCalculateListener;

importcom.runqian.report4.usermodel.DataSetConfig;

importcom.runqian.report4.usermodel.DataSetMetaData;

importcom.runqian.report4.usermodel.SQLDataSetConfig;

importcom.sun.jmx.snmp.Timestamp;

publicclassCalcListenerWriteSql2 extendsAbstractCalculateListener {

publicvoidbeforeCalculate() throwsException {

}

publicvoidafterCalculate() throwsException {

/**获取数据集名称和sql部分**/

Map<String, String> dsMap = newHashMap<String, String>();// 初始化存放数据集名,数据sqlmap

DataSetMetaData dsmd = report.getDataSetMetaData(); // 获取数据集元对象

intdsNum = dsmd.getDataSetConfigCount(); // 获取数据集个数

DataSetConfig dsc = null;

String dsName = “”;

SQLDataSetConfig sdsc = null;

for(inti = 0; i < dsNum; i++) {

String newSql = “”;// 不带问号的sql

dsc = dsmd.getDataSetConfig(i);

dsName = dsc.getName();// 取数据集名字

sdsc = (SQLDataSetConfig) dsmd.getDataSetConfig(i);

newSql = getDsSql(sdsc);

//Map中数据格式:key=数据集名;value=完整sql

dsMap.put(dsName, newSql);

}

/**获取报表名称,登录人ID,访问报表时间等信息**/

String raqName = (String)request.getAttribute(“raqName”);//报表名称

String userID = (String)request.getAttribute(“userID”);//用户ID

DateFormat df_now = DateFormat.getDateTimeInstance();

String now = df_now.format(newDate(System.currentTimeMillis()));//访问该报表时间

//*****************【可能需要修改部分开始】————————–//

/**判断是要新生成xml,还是读取本月的**/

String currDate = “”;//当前年月日

String firstDay = “”;//每月第一天

String currYM = “”;//当前月份

//判断当前日期是不是每月一号

String[] temp = now.split(” “);//空格分割出日期、时间

String[] date = temp[0].split(“-”);//-号分隔出年月日

for(inti=0;i<date.length-1;i++){//拼好年月

currDate += (date[i]+“-”);

firstDay += (date[i]+“-”);

}

currDate += date[date.length-1];

firstDay += “1″;

currYM += (date[0]+“-”);

currYM +=(date[1]);

String xmlPath = request. getRealPath (“\\”)+“reportInfo”+File.separator+currYM+“.xml”;

File f = newFile(xmlPath);

if(!f.exists()){//以年月命名的xml文件不存在,需要创建XML

System.out.println(currYM+“.xml不存在,正在创建……”);

createXML(dsMap,raqName,userID,now,currYM);//创建xml

System.out.println(创建XML结束!);

}else{//否则,以年月命名的xml文件存在,读取xml追加信息

System.out.println(currYM+“.xml已存在,正在修改……”);

modifyXML(dsMap,raqName,userID,now,currYM);//修改xml

//createXML(dsMap,raqName,userID,now,currYM);

System.out.println(修改XML结束!);

}

//—————-【可能需要修改部分结束】************************/

}

/**

*获取处理后sql语句,即不带问号的完整sql

*@paramsdsc

*@return

*@throwsException

*/

publicString getDsSql(SQLDataSetConfig sdsc) throwsException{

String finalSql = “”;//处理好的sql,返回

Map<Integer, String> paramMap = getParam(sdsc);//取该数据集参数值

String sql = sdsc.getSQL();// 取数据集sql

String[] sqlArr = sql.split(“\\u003F”);// split问号,问号需要转义

for(intj=0;j<sqlArr.length-1;j++){

finalSql = finalSql+sqlArr[j]+paramMap.get(j);

}

finalSql = finalSql + sqlArr[sqlArr.length-1];

returnfinalSql;

}

/**

*此方法用于获取该数据集的所有参数,将其位置和值存在map

*@paramsdsc

*@return

*@throwsException

*/

publicMap<Integer,String> getParam(SQLDataSetConfig sdsc)throwsException{

Map<Integer, String> paramMap = newHashMap<Integer, String>();// 存放参数值和参数位置

intparamNum = sdsc.getParamCount();// 取每个数据集中参数个数

for(intj = 0; j < paramNum; j++) {

String paramExp = sdsc.getParamExp(j); // 取每个数据集中参数表达式

//System.out.println(“” + j + “个参数:” + paramExp);

Expression exp = newExpression(context, paramExp);

Object afterCalcObj = exp.calculate(context, false);

/**判断参数类型**/

// 字符串

if(afterCalcObj instanceofString) {

paramMap.put(j, “‘”+ afterCalcObj.toString() + “‘”);// 字符串则拼单引号和值进去

// 以下是数值型

} elseif(afterCalcObj instanceofInteger) {

paramMap.put(j, afterCalcObj.toString());//

} elseif(afterCalcObj instanceofShort) {

paramMap.put(j, afterCalcObj.toString());//

} elseif(afterCalcObj instanceofLong) {

paramMap.put(j, afterCalcObj.toString());//

} elseif(afterCalcObj instanceofBigInteger) {

paramMap.put(j, afterCalcObj.toString());//

} elseif(afterCalcObj instanceofFloat) {

} elseif(afterCalcObj instanceofDouble) {

paramMap.put(j, afterCalcObj.toString());//

} elseif(afterCalcObj instanceofBigDecimal) {

paramMap.put(j, afterCalcObj.toString());//

// 以下是日期型

// ******************【可能要修改的部分开始】——————————–

// 此处采用oracleto_date函数将字符串转为日期类型,使用者需根据自身数据库情况采用对应的函数和日期格式

} elseif(afterCalcObj instanceofDate) {

DateFormat df = newSimpleDateFormat(“yyyy-MM-dd”);

String paramMapValue = “to_date(‘”

+ df.format(afterCalcObj) + “‘,’yyyy-MM-dd’)”;// 需要修改行

paramMap.put(j, paramMapValue);

} elseif(afterCalcObj instanceofTime) {

DateFormat df = newSimpleDateFormat(“hh:mm:ss”);

String paramMapValue = “to_date(‘”

+ df.format(afterCalcObj) + “‘,’hh:mm:ss’)”;// 需要修改行

paramMap.put(j, paramMapValue);

} elseif(afterCalcObj instanceofTimestamp) {

DateFormat df = newSimpleDateFormat(“yyyy-MM-dd hh:mm:ss”);

String paramMapValue = “to_date(‘”

+ df.format(afterCalcObj)

+ “‘,’yyyy-MM-dd hh:mm:ss’)”;// 需要修改行

paramMap.put(j, paramMapValue);

// ——————【可能要修改的部分结束】********************************

// 布尔值

} elseif(afterCalcObj instanceofBoolean) {

System.out.println(参数类型为布尔值,若使用请修改程序!);

// 组类型

} elseif(afterCalcObj instanceofArrayList) {

ArrayList al_afterCalcObj = (ArrayList)afterCalcObj;

Object element = al_afterCalcObj.get(0);//ArrayList里一个元素,看是什么类型

if(element instanceofString){//字符串

String paramMapValue=“”;

for(inti=0;i<al_afterCalcObj.size()-1;i++){

paramMapValue = “‘”+al_afterCalcObj.get(i)+“‘,’”;

}

paramMapValue = paramMapValue +al_afterCalcObj.get(al_afterCalcObj.size()-1)+“‘”;

paramMap.put(j, paramMapValue);

}else{//其他类型,不需要加单引号的,由于日期组没有意义,所以不做判断

String paramMapValue=“”;

for(inti=0;i<al_afterCalcObj.size()-1;i++){

paramMapValue = al_afterCalcObj.get(i)+“,”;

}

paramMapValue = paramMapValue +al_afterCalcObj.get(al_afterCalcObj.size()-1);

paramMap.put(j, paramMapValue);

}

}

}

returnparamMap;

}

/**

*根据相关信息创建XML文件,文件名为yyyy-MM.xml

*@parammap存放数据集名和sql

*@paramraqName报表名

*@paramuserID用户ID

*@paramnow当前日期时间

*@paramcurrYM当前年月

*/

publicvoidcreateXML(Map<String,String> map,String raqName,String userID,String now,String currYM){

Document document = DocumentHelper.createDocument(); //创建文档实例

document.addComment(“create time:”+now);//添加注释:文档创建时间

Element root = document.addElement(“messageRoot”);//创建根元素messageRoot

//catalogElement.addProcessingInstruction(“target”,”text”);

Element message = root.addElement(“message”);//根节点上添加message元素

Element time=message.addElement(“time”);//message节点上添加time元素

time.setText(now);//设置time元素文本

Element user_id = message.addElement(“userID”);

user_id.setText(userID);

Element raq_name = message.addElement(“raqName”);

raq_name.setText(raqName);

//遍历HashMap,取key-数据集名;value-sql

Iterator iter = map.entrySet().iterator();

while(iter.hasNext()) {

Map.Entry entry = (Map.Entry) iter.next();

String key = entry.getKey().toString();

String value = entry.getValue().toString();

Element sql = message.addElement(“sql”);//message上添加sql元素

sql.addAttribute(“dsName”,key);//数据集名放到sql节点的dsName属性中

sql.setText(value);//sql内容放到sql节点内容中

}

try{

String realPath = request. getRealPath (“”);

if(!“\\”.equals(realPath.trim().charAt(realPath.length()-1))){

realPath += “\\”;

}

//***************【可能需要修改部分开始】—————–//

//xml文件名当前年月;文件目录在应用根目录的reportInfo下,可修改

String xmlPath = realPath +“reportInfo\\”+currYM+“.xml”;

newFile(realPath+“reportInfo”).mkdir();//创建reportInfo目录

//—————【可能需要修改部分结束】*****************//

OutputFormat format = OutputFormat.createPrettyPrint();

format.setEncoding(“utf-8″);//设置xml编码

/**重要:此处需使用FileOutputStream防止中文乱码*/

//XMLWriter output = new XMLWriter(new FileWriter( new File(xmlPath)),format);

XMLWriter output = newXMLWriter(newFileOutputStream( newFile(xmlPath)),format);

/**重要:避免xml内容被转义*/

//output.setEscapeText(false);

output.write( document );

output.close();

}

catch(IOException e){System.out.println(e.getMessage());}

}

/**

*用于向现有xml文件中追加信息

*@parammap

*@paramraqName

*@paramuserID

*@paramnow

*@paramcurrYM

*/

publicvoidmodifyXML(Map<String,String> map,String raqName,String userID,String now,String currYM){

//取应用真实路径

String realPath = request. getRealPath (“”);

if(!“\\”.equals(realPath.trim().charAt(realPath.length()-1))){

realPath += “\\”;

}

//***************【可能需要修改部分开始】—————–//

//xml文件名当前年月;文件目录在应用根目录的reportInfo下,可修改

String inputXml = realPath +“reportInfo\\”+currYM+“.xml”;

//—————【可能需要修改部分结束】*****************//

SAXReader saxReader = newSAXReader();

try{

Document document = saxReader.read(inputXml);//读入xml

Element root = document.getRootElement();//取根节点

Element message = root.addElement(“message”);//根节点上添加message元素

Element time=message.addElement(“time”);//message节点上添加time元素

time.setText(now);//设置time元素文本

Element user_id = message.addElement(“userID”);

user_id.setText(userID);

Element raq_name = message.addElement(“raqName”);

raq_name.setText(raqName);

//遍历HashMap,取key-数据集名;value-sql

Iterator iter = map.entrySet().iterator();

while(iter.hasNext()) {

Map.Entry entry = (Map.Entry) iter.next();

String key = entry.getKey().toString();

String value = entry.getValue().toString();

Element sql = message.addElement(“sql”);//message上添加sql元素

sql.addAttribute(“dsName”,key);//数据集名放到sql节点的dsName属性中

sql.setText(value);//sql内容放到sql节点内容中

}

OutputFormat format = OutputFormat.createPrettyPrint();

/**重要:此处需使用FileOutputStream防止中文乱码*/

//XMLWriter output = new XMLWriter(new FileWriter( new File(xmlPath)),format);

XMLWriter output = newXMLWriter(newFileOutputStream( newFile(inputXml)),format);

/**重要:避免xml内容被转义*/

//output.setEscapeText(false);

output.write( document );

output.close();

} catch(DocumentException de) {

de.printStackTrace();

} catch(IOException ioe){

ioe.printStackTrace();

}

}

}