因为我们项目是以老师发布的资源(包括文档和视频)为中心的网站,所以在线文档也就成为了很重要的一环~解决这个技术难点是我在实习过程中体会最深的一件事。这个是最终的效果
大家可以看到左上角的print2flash,这不是一个插件的名字,而是一个转换工具。我也不想帮他卖广告= =无奈的是用他转换出来的swf都有这个。
我随便上网搜了一下,发现浏览器支持播放的基本上就只有pdf和swf。而我想实现的是老师上传的pdf,word,excel,ppt等文件的在线浏览,很明显要在线浏览office的文档不是那么简单的事情。我了解到虽然也有方法直接浏览office的文档,但是这对浏览器要求严格,所以最好的方法还是把这些office文档转换成pdf了。
①初试FlashPaper
我找到一个使用FlashPaper转换格式的demo,具体的方法是在程序里面用System.Diagnostics.Process这个类实现调用FlashPaper的server.exe文件。
②print2flash驾到
但是问题来了~他只支持32位系统,我不希望可扩展性这么差。于是我去找到了print2flash这款软件,同样有p2fServer.exe文件,只是传参格式有点差异。他有x64,x86两个版本,我下载了x64的,下面是调用它的代码:
private static void ConverToSWF(string oldFile, string playFile) { System.Diagnostics.Process pc = new System.Diagnostics.Process(); pc.StartInfo.FileName = localPath + @"\DATA\Print2Flash3_64\p2fServer.exe"; pc.StartInfo.Arguments = string.Format("{0} {1}", oldFile, playFile); pc.StartInfo.CreateNoWindow = true; pc.StartInfo.UseShellExecute = false; pc.StartInfo.RedirectStandardInput = false; pc.StartInfo.RedirectStandardOutput = false; pc.StartInfo.RedirectStandardError = true; pc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; pc.Start(); pc.WaitForExit(); pc.Close(); pc.Dispose(); }
因为找到了这个软件让我很快的在本地实现了格式转换(就是每次老师上传的时候都调用这段代码把已经上传到服务器的文档转换成swf),我就着手去弄其他东西了,然后?等到所有东西基本都完成后我把项目发布并且部署到IIS上面,问题来了= =根本没有调用到这个程序!我灰常的疑惑,于是上网各种查资料,才发现这样的做法根本就不可行,有人说”你这样做不是木马么?“在这里我首先意识到的是用VS自带的IIS在本地实现的功能跟真正的网站并不一定一样,我不应该这么迟才去部署网站。
③微软office类库出动
好了,既然用调用本地exe的方法不行,那我不如就用微软提供的类库吧,跟我需要用到的三种office文件的命名空间,还有一个COM类库。
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;
上网找了些例子,很快搞定,因为我用的是参考petshop的三层架构,要改的只是一个cs文件,本地测试没有问题。然后部署到IIS,于是他出现了:错误: 80070005 检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件时失败..这东西碉堡了,我对着这句话足足两天,因为网上给出的方法根本解决不了我的问题。你们可以把这个随便复制来百度一下或者google一下,会发现说的解决方法都是同一种,就是在组件服务里面(详细版:控制面板–管理工具–组件服务–计算机–我的电脑–DCom配置–)分别找到三个office并且修改他们的权限。可以看到百度里面说的都是xp或者win7,我的机子是win8…orz,反正我都改了,就是不行!看来,服务器不能用太新的系统啊,太新的系统一是不确保稳定,二是网上能找到对你有帮助的资料也就相对少了很多
④转换成html?
在这之后,我还试过用微软的类库把office文档转换成html,心想这样或许能解决问题。尝试后还是看到上面那一段红色的字= =我都快崩溃了,很快要交项目了,肿么酱紫啊你 {000209FF-0000-0000-C000-000000000046} 你是什么东西啊
⑤Web Service能拯救我么?
我甚至新建了一个web service项目,把调用office转换的类库的方法放在里面,在调用方法的时候直接调用这个项目里封装好的带Asyn的异步方法。还好搞WP的时候老师教过,只要封装好方法就好了,在需要调用web service的网站项目搜索service并且添加到项目中。然后在项目里的cs文件using对应的命名空间,创建一个service的对象,用这个对象调用异步方法。结果依然是美丽的 {000209FF-0000-0000-C000-000000000046}想想也是,虽然我的项目网站里面没有涉及到权限问题了,可是web service项目里也有涉及到,这个web service的服务器依然是本机
⑥我为什么需要那么高的权限
这样又过了一天,我突然觉得这样也许也并不安全,无论是客户端调用服务端的程序还是调用需要这么高权限的类库都不是很好的方法,我不应该在一棵树上吊死。可是要我放弃?我做不到,时间只剩下两天不到。我苦恼了半天突然想起为什么我要转换个格式为什么一定要关客户端的事,想来想去做这种事本来需要的安全级别就不应该这么高啊不是吗。我在web service调用的也是异步方法,那我为什么不把转换的工作和上传分开来呢?我的缺点就是虽然在小幅度变动的时候很灵活,可是却不会从大方向上做出改变。因为一旦钻进了牛角尖小幅度的“灵活变动”已经是完全没有意义了。
⑦线程轮询,再次使用print2flash
那么现在只有一个问题要解决,服务器怎么才能知道有文档需要转换,这个就简单了,线程不就解决了吗。我相信对一个正常的服务器来说,开一个小的线程轮询检查是否有文档没有被转换是一件消耗并不大的事情。好办!立刻把他实现了
//这个是全局的一个线程对象 Thread myThread = new Thread(swf); //这个是检查轮询的方法 private static void swf() { while (true) { foreach (string SourcePath in Directory.GetFiles(DocumentPath)) { string Extension = Path.GetExtension(SourcePath); string SWFfile = SourcePath.Replace(Extension, ".swf"); string PDFfile = SourcePath.Replace(Extension, ".pdf"); if (Extension != ".swf" && Extension != ".pdf" && !File.Exists(SWFfile) && !File.Exists(PDFfile)) { ConverToSWF(SourcePath, SWFfile); } } } } //可以看到上面调用的是我们一开始就使用的ConverToSWF方法
OK,终于实现了我想要的效果。服务器是需要一直开着这个线程的,我把他写在一个winform程序里面,在测试的时候打开他。要顺便说下这样写代码有两个地方不好,是建议改动的。第一是检查时不应该完全从头开始,这样虽然避免了有时候被漏掉的文档总能被转换过来,但是这样效率太低了,应该想方法记录已经转换过格式的文档。第二是检查扩展名的时候应该直接检查是不是你需要转换的格式(doc,docx,xls,xlsx,ppt,pptx)因为你难保有其他奇怪的东西混进来,我在测试的时候就因为有一个快捷方式而把转换程序搞停了。由于我时间太紧,所以这两个东西还没改就交给了老师~~
这个难题对我的启发很深,让我知道自己有多嫩,也让我成长了很多。
幸苦了,小虫~ 你的努力是有价值的~