package com.ycsoft.report.query;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.ycsoft.commons.exception.ReportException;
import com.ycsoft.commons.helper.LoggerHelper;
import com.ycsoft.commons.helper.StringHelper;
import com.ycsoft.commons.helper.ZipHelper;
import com.ycsoft.report.bean.RepHead;
import com.ycsoft.report.commons.CacheInput;
import com.ycsoft.report.commons.CacheOutput;
import com.ycsoft.report.commons.FileObjectInputStream;
import com.ycsoft.report.commons.FileObjectOutputStream;
import com.ycsoft.report.commons.ReportConstants;
import com.ycsoft.report.commons.ResultExcel;
import com.ycsoft.report.commons.StringUtil;
import com.ycsoft.report.db.ConnContainer;
import com.ycsoft.report.dto.InitQueryDto;
import com.ycsoft.report.query.sql.AnalyseMemoryKey;
import com.ycsoft.report.query.treequery.DimKeyContainer;
/**
* 通用的查询结果集
*
* @author new
*
*/
public class QueryResultCommon implements QueryResult {
private static final long serialVersionUID = -3458355170580312345L;
// 总行数
protected int rows = 0;
protected String rep_id=null;
protected String query_id = null;
protected String database = null;
private Date visit_date=new Date();
//列导出配置
private Integer[] export_cols=null;
protected String rep_type=null;
private boolean sum_sign=false;
//结果集 列属性
class QueryRsmd {
protected String ColumnName = null;
// sql结果集中列的类型
protected String TypeName = null;
//列类型是否数值型
protected boolean isnumber=false;
// 某行某列的值
protected Object ColumnValue = null;
protected String OlapType=null;
// 分组统计使用的参数
protected boolean isgroupkey=false;//是否分组定义列
protected boolean isgroupbycolumn=false;//是否分组列
protected boolean isgroup = false;//分组统计数据列
protected double group = 0;
// 末尾合计使用的参数
protected boolean istotal = false;
protected double total = 0;
//列id内存转换
protected boolean ismemory=false;
protected Map<String,String> memorymap=null;
public Object getMemoryValue(Object value){
if(ismemory){
String temp=null;
if(isnumber)
value=value.toString();
temp=memorymap.get(value);
if(temp==null)
return value;
else
return temp;
}
return value;
}
}
private String group;
private String[] total;
protected QueryResultCommon(InitQueryDto qdto,boolean do_exec) throws ReportException {
instance(qdto,do_exec);
}
/**
* 通用查询
*
* @param qdto
* @throws ReportException
*/
public QueryResultCommon(InitQueryDto qdto) throws ReportException {
instance(qdto,true);
}
private void instance(InitQueryDto qdto, boolean do_exec) throws ReportException {
this.query_id=qdto.getQuery_id();
this.database=qdto.getDatabase();
this.rep_type=qdto.getRep_type();
this.rep_id=qdto.getRep_id();
group=qdto.getGroup();
total=qdto.getTotals();
if (rep_type.endsWith(ReportConstants.REP_TYPE_QUIEE))
total = null;
if(do_exec)
execute(qdto.getSql());
}
/**
* 创建缓存输出流
* @return
* @throws IOException
* @throws ReportException
*/
protected CacheOutput createCacheOutput() throws IOException, ReportException{
return new FileObjectOutputStream(ReportConstants.REP_TEMP_TXT+ query_id);
}
protected void execute(String sql) throws ReportException{
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
CacheOutput foo = null;
try {
foo =this.createCacheOutput();
conn = ConnContainer.getConn(database);
stmt = conn.createStatement();
stmt.setFetchSize(1000);
LoggerHelper.debug(this.getClass(),sql);
rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
List<QueryRsmd> qrlist=this.createQRList(rsmd);
// 结果集字段属性
//获得分组标志,分组保存标志
boolean group_sign=false,groupsave_sign=true;
for(QueryRsmd qr:qrlist)
group_sign=qr.isgroupbycolumn||group_sign;
//快逸报表不能有分组统计
if(rep_type.equals(ReportConstants.REP_TYPE_QUIEE))
group_sign=false;
// 设置文件头
List<List<RepHead>> headlist=this.createHead(qrlist);
foo.writeHead(headlist);//保存到文件
List<Object> queryresult=null;//一条查询结果
while (rs.next()) {
// 一行查询结果
queryresult = new ArrayList<Object>(rsmd
.getColumnCount());
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
QueryRsmd qr = qrlist.get(i - 1);
Object value = rs.getObject(i);
if (value == null)
value = "";
//列转换处理
value=qr.getMemoryValue(value);
queryresult.add( value);
// 处理合计项
if (qr.istotal)
qr.total = qr.total + rs.getDouble(i);
//分组sum
if(qr.isgroup)
qr.group=qr.group+rs.getDouble(i);
//分组列
if(qr.isgroupbycolumn){
if(!groupsave_sign&&!value.equals(qr.ColumnValue)){
foo.writeObject(this.getGroup(qrlist));
rows++;
groupsave_sign=true;
}
qr.ColumnValue=value;
}
}
// 把一行查询结果写入文件
foo.writeObject(queryresult);
rows++;
//分组合计保存标志
groupsave_sign=false;
}
//最后一行的分组统计
if(group_sign&&queryresult!=null){
foo.writeObject(this.getGroup(qrlist));
rows++;
}
//把最后的合计行写入
//明细报表并存在统计列
if(isExecTotal()){
List<Object> totallist= getTail(qrlist);
foo.writeObject(totallist);
rows++;
this.sum_sign=true;
}
} catch (SQLException e) {
throw new ReportException(e,sql);
} catch (IOException e) {
throw new ReportException(e);
} catch (Exception e) {
throw new ReportException(e);
} finally {
try {
if (foo != null){
foo.close();
foo=null;
}
} catch (Exception e1) {
}
try {
if (rs != null){
rs.close();
rs=null;
}
} catch (Exception e) {
}
try {
if (stmt != null){
stmt.close();
stmt=null;
}
} catch (Exception e) {
}
try {
if (conn != null){
conn.close();
conn=null;
}
} catch (Exception e) {
}
}
}
@SuppressWarnings("unchecked")
public List<List<String>> getPage(Integer start, Integer limit)
throws ReportException {
CacheInput foi = null;
if (start > this.rows || start < 0 || limit <= 0)
throw new ReportException("page_index start or limit error.");
try {
foi = this.createCacheInput();// new FileObjectInputStream(ReportConstants.REP_TEMP_TXT + query_id);
List<List<String>> pagelist = new ArrayList<List<String>>(limit);
List<String> list = null;
int i = 0;
int min_i = start;
int max_i = start + limit;
//跳过查询头
foi.readHead();
while ((list = (List<String>) foi.readObject()) != null) {
if (i >= min_i){
//合计行判断
if(this.sum_sign&&i==this.rows-1)
list.add("T");
else
list.add("F");
pagelist.add(list);
}
i++;
if (i >= max_i)
break;
}
return pagelist;
} catch (IOException e) {
throw new ReportException(e);
} catch (ClassNotFoundException e) {
throw new ReportException(e);
} finally {
try {
if (foi != null){
foi.close();
foi=null;
}
} catch (Exception e) {
}
}
}
/**
* 最后一行是合计行标记
*/
public boolean getTailSumRowSign(){
return this.sum_sign;
}
/**
* 获取合计行
* @param qrlist
* @return
*/
private List<Object> getTail(List<QueryRsmd> qrlist) {
List<Object> taillist = new ArrayList<Object> (qrlist.size());
for(int i=0;i<qrlist.size();i++){
QueryRsmd qr =qrlist.get(i);
if (qr.istotal){
BigDecimal BDtotal=new BigDecimal(qr.total).setScale(2, BigDecimal.ROUND_HALF_UP);
taillist.add(i==0?"合计"+BDtotal.toString():BDtotal);
}else
taillist.add(i==0?"合计":"");
}
return taillist;
}
/**
* 获取分组行
* @param qrlist
* @return
*/
private List<Object> getGroup(List<QueryRsmd> qrlist) {
List<Object> taillist = new ArrayList<Object> (qrlist.size());
for(int i=0;i<qrlist.size();i++){
QueryRsmd qr =qrlist.get(i);
if (qr.isgroup){
BigDecimal BDgroup=new BigDecimal(qr.group).setScale(2, BigDecimal.ROUND_HALF_UP);
taillist.add(BDgroup);
qr.group=0;
}else if(qr.isgroupkey)
taillist.add("小计");
else taillist.add("");
}
return taillist;
}
public String getDatabase() {
return this.database;
}
public String getQueryId() {
return this.query_id;
}
protected CacheInput createCacheInput() throws IOException, ReportException{
return new FileObjectInputStream(ReportConstants.REP_TEMP_TXT+ query_id);
}
/**
* 获取查询头
*/
public List<List<RepHead>> getHead() throws ReportException {
CacheInput foi = null;
try {
foi = createCacheInput();
List<List<RepHead>> list=(List<List<RepHead>>) foi.readHead();
if(list==null)
throw new ReportException("rephead is null");
return list;
}catch (IOException e) {
throw new ReportException(e);
} catch (ClassNotFoundException e) {
throw new ReportException(e);
} finally {
try {
if (foi != null){
foi.close();
foi=null;
}
} catch (Exception e) {
}
}
}
public void updateVisitDate() {
this.visit_date = new Date();
}
public Date getVisitDate() {
return visit_date;
}
public int getRowSize() {
return rows;
}
public void clear() {
File file = new File(ReportConstants.REP_TEMP_TXT+ query_id);
if (file.exists())
file.delete();
file = new File(ReportConstants.REP_TEMP_TXT + query_id + ".xls");
if (file.exists())
file.delete();
file = new File(ReportConstants.REP_TEMP_TXT +query_id + ".zip");
if (file.exists())
file.delete();
file = new File(ReportConstants.REP_TEMP_TXT +query_id + "_index");
if (file.exists())
file.delete();
}
public String getRepId() {
return rep_id;
}
/**
* 导出快逸报表初始化数据源zip
* @return
* @throws ReportException
*/
private String exportRaq() throws ReportException{
FileObjectOutputStream foo=null;
try {
foo=new FileObjectOutputStream(ReportConstants.REP_TEMP_TXT+this.query_id+ReportConstants.INDEX);
//写入查询结果集对象
foo.writeObject(this);
//写入查询维度容器
foo.writeObject(DimKeyContainer.getDimkeymap());
foo.close();
foo=null;
String[] files={(ReportConstants.REP_TEMP_TXT+this.query_id),(ReportConstants.REP_TEMP_TXT+this.query_id+ReportConstants.INDEX)};
ZipHelper.zip(files, ReportConstants.REP_TEMP_TXT, this.query_id);
return ReportConstants.REP_TEMP_TXT+this.query_id+ReportConstants.ZIPPOSTFIX;
} catch (IOException e) {
throw new ReportException(e);
}finally{
try {
if (foo != null){
foo.close();
foo=null;
}
} catch (Exception e1) {
}
}
}
/**
* 导出单个excel文档
* @param query_id
* @return
* @throws ReportException
*/
private static String exportXls(String query_id,Integer... export_cols) throws ReportException{
ResultExcel re=new ResultExcel(query_id,export_cols);
return re.getExportFile();
}
/**
* 导出Zip,加同步标志(保证整个系统只能执行一个Zip包压缩)
* @param query_id
* @return
* @throws ReportException
*/
private synchronized static String exportZip(String query_id,Integer... export_cols) throws ReportException{
ResultExcel re=new ResultExcel(query_id,export_cols);
return re.getExportFile();
}
/**
* 判断导出配置是否一致
* @param col_indexs
* @return
*/
private boolean isexportcolssame(Integer... col_indexs){
if(this.export_cols==null&&col_indexs==null)
return true;
if(this.export_cols!=null&&col_indexs!=null&&this.export_cols.length==0&&col_indexs.length==0)
return true;
if(this.export_cols!=null&&col_indexs!=null&&this.export_cols.length==col_indexs.length){
Map<String,Integer> a=new HashMap<String,Integer>();
Map<String,Integer> b=new HashMap<String,Integer>();
for(Integer o:this.export_cols)
a.put(o.toString(), o);
for(Integer o:col_indexs)
b.put(o.toString(), o);
for(Integer o:this.export_cols){
if(!b.containsKey(o.toString()))
return false;
}
for(Integer o:col_indexs){
if(!a.containsKey(o.toString()))
return false;
}
return true;
}
return false;
}
/**
* 返回导出文档的全文件名
* col_indexs为列索引数组,值为空表示导出快逸初始化数据源
* @throws ReportException
*/
public String export(Integer... col_indexs) throws ReportException {
this.updateVisitDate();
//判断导出文件是否已经存在
String exportfile=ReportConstants.REP_TEMP_TXT+this.query_id+ReportConstants.ZIPPOSTFIX;
if(new File(exportfile).exists()&&this.isexportcolssame(col_indexs))
return exportfile;
exportfile=ReportConstants.REP_TEMP_TXT+this.query_id+ReportConstants.EXCELPOSTFIX;
if(new File(exportfile).exists()&&this.isexportcolssame(col_indexs))
return exportfile;
this.export_cols=col_indexs;
//执行导出
if(ReportConstants.REP_TYPE_QUIEE.equals(this.rep_type)){
//导出快逸初始化用数据源
return this.exportRaq();
}else{
//导出明细报表
//当生成excel文档需要zip压缩时,现在只能同时执行一个压缩(使用同步实现或其他省资源的方式
if(this.rows>ReportConstants.WORKBOOKMAXROWS)
return exportZip(this.query_id,this.export_cols);
else
return exportXls(this.query_id,this.export_cols);
}
}
/**
* 创建表头
* @param qrlist
* @return
*/
protected List<List<RepHead>> createHead(List<QueryRsmd> qrlist) {
List<List<RepHead>> headlist = new ArrayList<List<RepHead>>();
List<RepHead> list = new ArrayList<RepHead>();
for (int i = 0; i < qrlist.size(); i++) {
QueryRsmd qr = qrlist.get(i);
RepHead rh = new RepHead();
rh.setCol_desc(qr.ColumnName);
rh.setCol_length(1);
rh.setCol_seq(i);
rh.setRow_seq(1);
rh.setOlap_type(qr.OlapType);
list.add(rh);
}
headlist.add(list);
return headlist;
}
/**
* 创建结果集的列属性
* 分组统计逻辑还存在问题
* @param rsmd
*/
protected List<QueryRsmd> createQRList(ResultSetMetaData rsmd)
throws SQLException {
List<QueryRsmd> qrlist = new ArrayList<QueryRsmd>(rsmd.getColumnCount());
//分组合计标志
boolean groupcolumn_sign=false,groupsum_sign=false;
if(StringHelper.isNotEmpty(group)){
groupcolumn_sign=true;
groupsum_sign=true;
}
for (int i = 0; i <rsmd.getColumnCount(); i++) {
QueryRsmd qr=new QueryRsmd();
//列数值属性
if("NUMBER".equals(rsmd.getColumnTypeName(i + 1))
|| "INTEGER".equals(rsmd.getColumnTypeName(i + 1)))
qr.isnumber=true;
qr.ColumnName = rsmd.getColumnName(i+1);
//内存ID转换
Map<String,String> mkmap=AnalyseMemoryKey.getMemoryMap(qr.ColumnName);
if(mkmap!=null&&mkmap.size()>0){
qr.ColumnName=AnalyseMemoryKey.getMemoryKeyDesc(qr.ColumnName);
qr.memorymap=mkmap;
qr.ismemory=true;
}//合计项设置
for(int j=0;total!=null&& j<total.length;j++){
if(qr.ColumnName.equals(total[j]))
qr.istotal=true;
}
//分组统计项目设置
if(groupsum_sign){
if(!groupcolumn_sign&&(rsmd.getColumnTypeName(i+1).equals("NUMBER")
||rsmd.getColumnTypeName(i+1).equals("INTEGER"))){
qr.isgroup=true;
}else if(groupcolumn_sign){
qr.isgroupbycolumn=true;
if(qr.ColumnName.equals(group)){
groupcolumn_sign=false;
qr.isgroupkey=true;
}
}
}
qrlist.add(qr);
}
//groupcolumn_sign=true 说明未找到分组列
if(groupcolumn_sign){
for(QueryRsmd qr:qrlist){
qr.isgroup=false;
qr.isgroupbycolumn=false;
}
}
return qrlist;
}
protected boolean isExecTotal() {
return total!=null;
}
private String qrkeys_sha1=null;
public String getQRSHA() {
return qrkeys_sha1;
}
public void setQRSHA(String qrkeys) throws ReportException {
try {
this.qrkeys_sha1=StringUtil.SHA1(qrkeys);
} catch (Exception e) {
throw new ReportException("sha1计算失败",e);
}
}
}