duhe
9 天以前 b16717b61d4804fcaeeb103f6602959eb5a5a0c6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
using System;
//using System.Collections;
using System.Text;
using System.Data;
using System.Configuration;
using System.IO;
using System.IO.Compression;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//以下枚举指定报表数据的格式类型
public enum ResponseDataType
{
    PlainText, //报表数据为XML或JSON文本,在调试时可以查看报表数据。数据未经压缩,大数据量报表采用此种方式不合适
    ZipBinary, //报表数据为XML或JSON文本经过压缩得到的二进制数据。此种方式数据量最小(约为原始数据的1/10),但用Ajax方式加载报表数据时不能为此种方式
    ZipBase64, //报表数据为将 ZipBinary 方式得到的数据再进行 BASE64 编码的数据。此种方式适合用Ajax方式加载报表数据
};
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// ReportQueryItem
public class ReportQueryItem
{
    public string QuerySQL;
    public string RecordsetName;
 
    public ReportQueryItem(string AQuerySQL, string ARecordsetName)
    {
        QuerySQL = AQuerySQL;
        RecordsetName = ARecordsetName;
    }
};
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// ReportDataBase
public class ReportDataBase
{
    //指定报表的默认数据类型,便于统一定义整个报表系统的数据类型
    //在报表开发调试阶段,通常指定为 ResponseDataType.PlainText, 以便在浏览器中查看响应的源文件时能看到可读的文本数据
    //在项目部署时,通常指定为 ResponseDataType.ZipBinary 或 ResponseDataType.ZipBase64,这样可以极大减少数据量,提供报表响应速度
    public const ResponseDataType DefaultDataType = ResponseDataType.PlainText; //PlainText ZipBinary ZipBase64 
 
    //将报表XML数据文本输出到HTTP请求
    public static void ResponseData(System.Web.UI.Page DataPage, ref string DataText, ResponseDataType DataType)
    {
        //报表XML数据的前后不能附加任何其它数据,否则XML数据将不能成功解析,所以调用ClearContent方法清理网页中前面多余的数据
        DataPage.Response.ClearContent();
 
        if (ResponseDataType.PlainText == DataType)
        {
            // 把xml对象发送给客户端
            //DataPage.Response.ContentType = "text/xml";
            DataPage.Response.Write(DataText);
        }
        else
        {
            //将string数据转换为byte[],以便进行压缩
            System.Text.UTF8Encoding converter = new System.Text.UTF8Encoding();
            byte[] XmlBytes = converter.GetBytes(DataText);
 
            //在 HTTP 头信息中写入报表数据压缩信息
            DataPage.Response.AppendHeader("gr_zip_type", "deflate");                  //指定压缩方法
            DataPage.Response.AppendHeader("gr_zip_size", XmlBytes.Length.ToString()); //指定数据的原始长度
            DataPage.Response.AppendHeader("gr_zip_encode", converter.HeaderName);     //指定数据的编码方式 utf-8 utf-16 ...
 
            // 把压缩后的xml数据发送给客户端
            if (ResponseDataType.ZipBinary == DataType)
            {
                DeflateStream compressedzipStream = new DeflateStream(DataPage.Response.OutputStream, CompressionMode.Compress, true);
                compressedzipStream.Write(XmlBytes, 0, XmlBytes.Length);
                compressedzipStream.Close();
            }
            else //ResponseDataType.ZipBase64
            {
                MemoryStream memStream = new MemoryStream();
                DeflateStream compressedzipStream = new DeflateStream(memStream, CompressionMode.Compress, true);
                compressedzipStream.Write(XmlBytes, 0, XmlBytes.Length);
                compressedzipStream.Close(); //这句很重要,这样数据才能全部写入 MemoryStream
 
                // Read bytes from the stream.
                memStream.Seek(0, SeekOrigin.Begin); // Set the position to the beginning of the stream.
                int count = (int)memStream.Length;
                byte[] byteArray = new byte[count];
                count = memStream.Read(byteArray, 0, count);
 
                string Base64Text = Convert.ToBase64String(byteArray);
                DataPage.Response.Write(Base64Text);
            }
        }
 
        //报表XML数据的前后不能附加任何其它数据,否则XML数据将不能成功解析,所以调用End方法放弃网页中后面不必要的数据
        DataPage.Response.End();
    }
}
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//class XMLReportData 产生报表需要的xml数据
public class XMLReportData
{
    //根据 DataSet 产生提供给报表需要的XML数据,参数DataType指定压缩编码数据的形式
    public static void GenDataSet(System.Web.UI.Page DataPage, DataSet ReportDataSet, ResponseDataType DataType)
    {
        string XMLText = ReportDataSet.GetXml();
        ReportDataBase.ResponseData(DataPage, ref XMLText, DataType);
    }
 
    //根据 DataTable 产生提供给报表需要的XML数据,参数DataType指定压缩编码数据的形式
    public static void GenDataTable(System.Web.UI.Page DataPage, DataTable mydt, ResponseDataType DataType)
    {
        DataSet ds = new DataSet();
        ds.Tables.Add(mydt);
        GenDataSet(DataPage, ds, DataType);
    }
 
    //根据IDataReader, 产生提供给报表需要的XML数据,其中的空值字段也会产生XML节点,参数DataType指定压缩编码数据的形式
    public static void GenNodeXmlDataFromReader(System.Web.UI.Page DataPage, IDataReader dr, ResponseDataType DataType)
    {
        string XMLText = "<xml>\n";
        while (dr.Read())
        {
            XMLText += "<row>";
            for (int i = 0; i < dr.FieldCount; ++i)
            {
                string FldName = dr.GetName(i);
                if (FldName == "")
                    FldName = "Fld" + i;
                XMLText += String.Format("<{0}>{1}</{0}>", FldName, HttpUtility.HtmlEncode(dr.GetValue(i).ToString()));
            }
            XMLText += "</row>\n";
        }
        XMLText += "</xml>\n";
 
        ReportDataBase.ResponseData(DataPage, ref XMLText, DataType);
    }
}
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//class JSONReportData 产生报表需要的 JSON 格式数据
public class JSONReportData
{
    //根据 DataSet 产生提供给报表需要的JSON数据,参数DataType指定压缩编码数据的形式
    public static void GenDataSet(System.Web.UI.Page DataPage, DataSet ReportDataSet, ResponseDataType DataType)
    {
        string Out = GenDetailText(ReportDataSet);
        ReportDataBase.ResponseData(DataPage, ref Out, DataType);
    }
 
    //根据 DataTable 产生提供给报表需要的JSON数据,参数DataType指定压缩编码数据的形式
    public static void GenDataTable(System.Web.UI.Page DataPage, DataTable dt, ResponseDataType DataType)
    {
        DataSet ds = new DataSet();
        ds.Tables.Add(dt);
        GenDataSet(DataPage, ds, DataType);
    }
 
    //根据 DataSet 产生提供给报表需要的JSON文本数据
    public static string GenDetailText(DataSet ds)
    {
        StringBuilder sbJSONText = new StringBuilder("{\n");
        foreach (DataTable dt in ds.Tables)
        {
            //"recordset":[
            sbJSONText.Append('"');
            sbJSONText.Append(dt.TableName); 
            sbJSONText.Append("\":[\n");
            foreach (DataRow dr in dt.Rows)
            {
                sbJSONText.Append('{');
                for (int i = 0; i < dt.Columns.Count; ++i)
                {
                    if (!dr.IsNull(i))
                    {
                        string Value;
                        if (dt.Columns[i].DataType.IsArray)
                        {
                            Value = Convert.ToBase64String((byte[])dr[i]);
                        }
                        else
                        {
                            Value = dr[i].ToString();
                            PrepareValueText(ref Value);
                        }
                        sbJSONText.AppendFormat("\"{0}\":\"{1}\",", dt.Columns[i].ColumnName, Value);
                    }
                }
                sbJSONText.Remove(sbJSONText.Length - 1, 1); //去掉每笔记录最后一个字段后面的","
                sbJSONText.Append("},\n");
            }
            sbJSONText.Remove(sbJSONText.Length - 2, 1); //去掉最后一条记录后面的","
            sbJSONText.Append("],\n");
        }
        sbJSONText.Remove(sbJSONText.Length - 2, 1); //去掉最后一记录集后面的","
        sbJSONText.Append("}");
 
        return sbJSONText.ToString();
    }
 
    //如果数据中包含有JSON规范中的特殊字符(" \ \r \n \t),多特殊字符加 \ 编码
    public static void PrepareValueText(ref string ValueText)
    {
        bool HasSpecialChar = false;
        foreach(char ch in ValueText)
        {
            if (ch == '"' || ch == '\\' || ch == '\r' || ch == '\n' || ch == '\t')
            {
                HasSpecialChar = true;
                break;
            }
        }
        if (HasSpecialChar)
        {
            StringBuilder NewValueText = new StringBuilder();
            foreach (char ch in ValueText)
            {
                if (ch == '"' || ch == '\\' || ch == '\r' || ch == '\n' || ch == '\t')
                {
                    NewValueText.Append( '\\');
                    if (ch == '"' || ch == '\\')
                        NewValueText.Append( ch  );
                    else if (ch == '\r')
                        NewValueText.Append( 'r' );
                    else if (ch == '\n')
                        NewValueText.Append( 'n' );
                    else if (ch == '\t')
                        NewValueText.Append( 't' );
                }
                else
                {
                    NewValueText.Append( ch  );
                }
            }
            ValueText = NewValueText.ToString();
        }
    }
}