基于B/S模式的网页报表打印方式的分析与实现

本文主题

     由于现在主流的B/S打印模式存在的固有的缺点,通过借鉴优秀报表软件和应用软件的模式,本文提出了利用VC++中的Automation功能实现办公软件网页打印控件,来解决不同报表工具间的差别。

前言

      在开发B/S模式的办公系统时,往往需要使用报表打印的功能,目前主流的报表软件对网页打印支持的没有像C/S那样完好,比如使用水晶报表的网页打印功能,用户只能等待报表输出到网页上之后再调用打印功能实现打印,在一些不需要看到输出内容或者报表输出与网页内显示的内容不一致的时候,这种方式就显得麻烦了。我现在使用IReport报表软件设计报表,前台进行打印的时候使用的是Applet的方式,这种方式固有的缺点是必须安装JRE运行时环境,而且为了去掉JRE的安全提示必须在JRE中安装一个安全文件。而水晶报表的模式是将报表导出到PDF中,再有用户调用PDF中的打印功能。

现状分析

      上面的两种方式都存在一个问题:Applet的方式必须安装JRE,一个JRE大小40M++,而且安装过程需要用户的介入,需要用户配置环境变量,对于那些对电脑不熟悉或者年龄比较大的用户来说是一件非常麻烦的事情;采用PDF的方式由于PDF远没有办公软件的普及面广,因此其应用也受到了限制。

     为了解决上面遇到的问题,本文提出了做出了如下的分析:

     1。办公软件如Word,Excel等普及面非常广泛;

     2。微软提供操作办公软件的类库,而且WPS也完美支持微软办公软件。

     3。采用CAB控件的形式可以实现在用户机器上面操作办公软件而不需要其他安全认证;

     4。主流的报表软件都提供导出到办公软件的功能。

     基于上面的问题,本文提出如下的解决方案:

     1.服务器端生成要导出的数据给报表软件模块。

     2.报表软件模块生成报表。

     3.报表软件模块使用导出功能将报表导出到办公软件中。

     4.将导出的文件暂存到服务器的临时目录中,并生成文件的访问地址。

     5.客户端采用异步请求的方式获取到服务端导出的报表文件地址。

     6.客户端控件接收服务器端文件地址,并开始下载远端文件到本地临时文件夹。

     7.客户端控件在文件下载完毕后调用该文件的打印功能,进行报表打印。

     8.打印成功执行后删除客户端的临时文件。

VC++利用Automation实现操作办公软件的网页控件

要实现办公自动化功能,首先需要添加办公软件的头文件,如word的头文件或excel的头文件。

添加方式:

对于VC6.0来说,打开class wizard, 然后选中automation,弹出以下界面:

image

     点击 "Add Class"按钮,会出现一个下拉菜单,只有2项,然后选择"from a type lib",此时弹出一个对话框,提示输入typelib文件。

     这些文件一般在你office的安装目录下,名字是msword.olb,选中后点OK, 就出现下面的对话框:

image

选择你需要的功能后,点击确定,生成如下的头文件:

image

实例演示

下面给出一个在我做的DLL里面操作Excel的实例:

/*
by:rush date:2011年7月8日 23:30:48
功能:按照微软的提供的函数进行打印操作
参数:文件路径
返回值:如果成功返回true,否则返回false
*/
//extern "C" __declspec(dllexport) BOOL CExcelPlusApp::PrintExcelByMSFunction(CString filePath)
BOOL PrintExcelByMSAPI(CString filePath)
{
	//加上这句表示是导出函数
	//AFX_MANAGE_STATE(AfxGetStaticModuleState());
	if(filePath.IsEmpty()){
		return FALSE;
	}
	CString testFilePath = filePath;
	if(!(testFilePath.Find(".et") > 0 
		|| testFilePath.Find(".xls") > 0 
		|| testFilePath.Find(".xlsx") > 0)){
        return FALSE;
	}
    try
    {
		CString filename = filePath;
		//*****
		//变量定义
		_Application app;    
		Workbooks books;
		_Workbook book;
		Worksheets sheets;
		_Worksheet sheet;
		Range range;
		Range iCell;
		LPDISPATCH lpDisp;    
		COleVariant vResult;
		COleVariant
			covTrue((short)TRUE),
			covFalse((short)FALSE),
			covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);    
		
		CoInitialize(NULL);  // 初始化com组件,必须的
		//创建Excel 2000服务器(启动Excel)
		if(!app.CreateDispatch("Excel.Application")) 
		{
			AfxMessageBox("无法启动Excel服务器!");
			CoUninitialize();
			return FALSE;
		}
		app.SetVisible(false);          //使Excel可见
		//app.SetUserControl(TRUE);      //允许其它用户控制Excel
		//*****   
		//打开c:\\1.xls
		books.AttachDispatch(app.GetWorkbooks());
		COleVariant covFileName;	
		covFileName.vt = VT_BSTR;	
		covFileName.bstrVal = filename.AllocSysString();	
		lpDisp = books.Open(filename,covOptional,covOptional,covOptional,covOptional,
			covOptional,covOptional,covOptional,covOptional,covOptional,covOptional,covOptional,
			covOptional,covOptional,covOptional);    	
		//*****
		//得到Workbook
		book.AttachDispatch(lpDisp);	
		//*****
		//得到Worksheets 
		sheets.AttachDispatch(book.GetWorksheets()); 
		//*****
		//得到当前活跃sheet
		//如果有单元格正处于编辑状态中,此操作不能返回,会一直等待
		lpDisp=book.GetActiveSheet();
		book.PrintOut(covOptional,covOptional,covOptional,covOptional,covOptional,covOptional,
			covOptional,covOptional);
		//*****
		//关闭所有的book,退出Excel 
		book.Close (covOptional,COleVariant(filename),covOptional);
		books.Close();   

		books.ReleaseDispatch();
		book.ReleaseDispatch();
		sheets.ReleaseDispatch();
		range.ReleaseDispatch();
		sheet.ReleaseDispatch();
		iCell.ReleaseDispatch();

		lpDisp->Release();

		app.SetUserControl(FALSE);
		app.Quit(); 
		app.ReleaseDispatch();
    }
    catch (CMemoryException* e)
    {
		char* err = new char[1024];
		e->GetErrorMessage(err,1024);
		AfxMessageBox(err);
		return FALSE;
    }
    catch (CFileException* e)
    {
		char* err = new char[1024];
		e->GetErrorMessage(err,1024);
		AfxMessageBox(err);
		return FALSE;
    }
    catch (CException* e)
    {
		char* err = new char[1024];
		e->GetErrorMessage(err,1024);
		AfxMessageBox(err);
		return FALSE;
    }
	return TRUE;
}

网页打印控件实现

如果想了解是怎么实现的,请查看我以前发布的资料,下面是传送门:---》》

VC6编写ActiveX控件全过程

ActiveX控件(.ocx .cab ..)数字签名全过程

编写带界面的ActiveX控件(CAB网页控件)全过程

利用javascript自动安装数字证书

OCX控件避免弹出安全警告的类

OCX控件打包成CAB并实现数字签名过程

参考资料

下面这些资料是我在查询如何使用办公自动化类的过程中用到的资料,以下资料全部来自于互联网:

关于EXCEL,方法类似。

利用automation对word和excel的操作是类似的。类的结构如下:

Application // 代表程序

Workbooks // 代表word所有文档

Workbook // 单个word文档

......

Worksheets // 代表excel表的集合

Worksheet //代表单个表

......

Range //活动区域

Cells / cell 单元格

Rows /row 行

Columns / column 列

Tables / table 表

Bookmarks / bookmark 标签

saveas 另存为

printout 打印

剩下的就不多讲了,直接给代码吧。

关于word的:

CoInitialize(NULL); // 初始化com组件,必须的

_Application wordApp;

if (!wordApp.CreateDispatch("Word.Application")) //将wordApp链接到word应用程序

{

CoUninitialize();

return FALSE;

}

... 

Documents docs = wordApp.GetDocuments(); // 获得word的文档集

_Document doc;

COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);

COleVariant vtTrue((short)TRUE), vtFalse((short)FALSE);

CString filename; //要打开的文件名字

if(Filename.Find(".dot",0) > 0) // 如果是后缀是.dot,表明为一个word模板

{

// add the template to the word 

COleVariant covFileName;

covFileName.vt = VT_BSTR;

covFileName.bstrVal = ReportFilename.AllocSysString();

doc = docs.Add(covFileName,vtOptional,vtOptional,vtOptional); // 调用add

} 

else

{

// 如果是一个.doc普通文档,新建一个新的文档,然后把这个文件添加进去

doc = docs.Add(vtOptional,vtOptional,vtOptional,vtOptional); 

// the selection will be released automatically.

Selection oSelection;

oSelection = wordApp.GetSelection();

//插入一个文件

oSelection.InsertFile(Filename.GetBuffer(ReportFilename.GetLength()),vtOptional,vtOptional,vtOptional,vtOptional);

Filename.ReleaseBuffer();

oSelection.DetachDispatch();

}

当然,你也可以直接用open来打开一个文件。有对应的open方法。

取得word的版本号。 2000对应9.0, 2002对应10.0, 2003对应11.0,2007对应12.0

CString sVersion = wordApp.GetVersion(); 

COleVariant tablebookmarkname(bookmarkName);

//取得word的标签

Bookmarks wordbookmarks = doc.GetBookmarks();

//根据标签名取得指定标签

Bookmark wordbookmark;

wordbookmark = wordbookmarks.Item(tablebookmarkname);

//取得区域

Range range ;

range = wordbookmark.GetRange();

// 取得区域相连的表

Tables ts = range.GetTables();

Table t = ts.Item(1);

Rows rows = t.GetRows();

Row row = rows.Item(1); // the index is starts 1, ,2...

Cells cells = row.GetCells();

int colcount = cells.GetCount();

Cell cell = t.Cell(2, k+1);

range = cell.GetRange();

CString inh = range.GetText();

row = rows.Add(vtOptional);

//设置文字

range.SetText(inhnew);

保存文件,注意版本不同,有可能导致接口不同。

COleVariant savefilename, fileformat;

if(sVersion == "9.0")

{

doc.SaveAs9(savefilename, vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,

vtOptional,vtOptional,vtOptional,vtOptional);

}

else if(sVersion == "10.0")

{

doc.SaveAs(&vNeuerName,& vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,

vtOptional,vtOptional,vtOptional,vtOptional,vtOptional, vtOptional,vtOptional,vtOptional,vtOptional);

} 

else if(sVersion == "11.0")

{

doc.SaveAs(&vNeuerName,& vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,vtOptional,

vtOptional,vtOptional,vtOptional,vtOptional,vtOptional, vtOptional,vtOptional,vtOptional,vtOptional);

}

//打印文件

doc.PrintOut(vtOptional,vtOptional,vtOptional
            ,vtOptional,vtOptional,vtOptional
            ,vtOptional,vtOptional,vtOptional
            ,vtOptional,vtOptional,vtOptional
            ,vtOptional,vtOptional,vtOptional
            ,vtOptional,vtOptional,vtOptional);

退出:

wordApp.Quit(vtOptional,vtOptional,vtOptional);

也可以用shellexcute打开和打印一个word文件。

2011年9月10日 10:22:49


如果觉得本文好的话就分享给你的朋友把!
原文地址:https://www.cnblogs.com/rushoooooo/p/2173029.html