将报表sql和参数输出到xml文件中
需求背景
客户要求能够将报表名称、报表数据集sql、报表参数值、访问报表时间、登录人信息等信息输出到xml文件中,以对该xml文件进行分析。
要求:1、sql是完整的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>();// 初始化存放数据集名,数据sql的map
再在该方法中获取数据集元对象以及数据集个数,通过循环数据集个数获取数据集名和通过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>();// 初始化存放数据集名,数据sql的map
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());//
// 以下是日期型
// ******************【可能要修改的部分开始】——————————–
// 此处采用oracle的to_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();
}
}
}