周 琴
(四川省科學(xué)技術(shù)信息研究所,成都 610016)
互聯(lián)網(wǎng)時(shí)代,文件傳輸服務(wù)已是Web 應(yīng)用系統(tǒng)的重要功能之一,用于完成信息的交互和共享。無論是企業(yè)的信息系統(tǒng)、還是電子政務(wù)系統(tǒng)、電子商務(wù)系統(tǒng)等,隨著應(yīng)用規(guī)模的擴(kuò)大,文件傳輸需求越來越多,要求越來越高,任務(wù)并發(fā)情況也越來越頻繁。而文件上傳/下載效率很容易受到文件大小和網(wǎng)絡(luò)帶寬影響,經(jīng)常因?yàn)槲募^大或者網(wǎng)絡(luò)中斷導(dǎo)致傳輸失敗,不得不重新傳輸。另外,文件傳輸服務(wù)作為一個(gè)常見的功能模塊,不同應(yīng)用之間存在重復(fù)開發(fā)的問題,增加了系統(tǒng)開發(fā)成本。同時(shí),開發(fā)者在實(shí)際開發(fā)過程中容易忽視它的重要性,導(dǎo)致文件傳輸?shù)男实拖?,傳輸?shù)陌踩院涂煽啃缘貌坏奖WC。如何在高并發(fā)環(huán)境中實(shí)現(xiàn)大文件穩(wěn)定、安全、可靠的傳輸是Web 應(yīng)用系統(tǒng)開發(fā)需要考慮的重要問題。
針對(duì)上述問題,本文基于Hessian 協(xié)議框架研發(fā)一套通用的文件傳輸服務(wù)系統(tǒng),能夠?yàn)橥獠烤W(wǎng)絡(luò)應(yīng)用提供高性能的獨(dú)立的文件傳輸和文件加工處理服務(wù),實(shí)現(xiàn)文件傳輸和加工處理與外部網(wǎng)絡(luò)應(yīng)用相互獨(dú)立,可跨平臺(tái)用于不同網(wǎng)絡(luò)環(huán)境中。本文將文件分片傳輸,可解決因文件過大導(dǎo)致傳輸失敗的問題。通過建立統(tǒng)一規(guī)范的文件傳輸服務(wù)接口,供不同外部應(yīng)用訪問,這樣能簡(jiǎn)化Web 應(yīng)用系統(tǒng)的設(shè)計(jì)并快速進(jìn)行開發(fā),同時(shí)也解決了不同應(yīng)用之間重復(fù)開發(fā)相同功能模塊的問題。Web 應(yīng)用系統(tǒng)通過訪問通用的接口與文件傳輸服務(wù)系統(tǒng)進(jìn)行交互,告知文件傳輸服務(wù)系統(tǒng)將要傳輸?shù)奈募脑吹刂泛湍康牡刂?,以及加工處理的具體任務(wù)。文件服務(wù)系統(tǒng)通過接口接收指令,獨(dú)立完成任務(wù)后,將文件傳輸服務(wù)狀態(tài)反饋給接口,Web 應(yīng)用系統(tǒng)通過接口來實(shí)時(shí)查看文件傳輸服務(wù)狀態(tài)。
在OSI網(wǎng)絡(luò)通信模型中,RPC協(xié)議跨越了傳輸層和網(wǎng)絡(luò)層,使得開發(fā)高可用的分布式應(yīng)用程序更加容易。近年來,基于RPC 協(xié)議的遠(yuǎn)程服務(wù)調(diào)用在分布式項(xiàng)目中應(yīng)用越來越廣泛,比如谷歌的gRPC、Facebook 的Thrift、阿里巴巴的Dubbo、新浪的Montan 以及Hessian、Avro、Ice等,各個(gè)框架都有其各自的優(yōu)缺點(diǎn)。本文選取Hessian 協(xié)議作為文件傳輸系統(tǒng)的遠(yuǎn)程通信架構(gòu),實(shí)現(xiàn)系統(tǒng)之間的數(shù)據(jù)傳送。它具有傳輸開銷小、網(wǎng)絡(luò)帶寬利用率高、數(shù)據(jù)傳遞效率高的特點(diǎn),能很好地滿足文件傳輸?shù)臄?shù)據(jù)通信需求。
Hessian 是由Caucho 公司開發(fā)的一種基于二進(jìn)制RPC 協(xié)議(Binary-RPC)的輕量級(jí)遠(yuǎn)程調(diào)用框架,采用自定義描述的二進(jìn)制傳輸協(xié)議,很適合發(fā)送二進(jìn)制數(shù)據(jù),利用它可以快速地開發(fā)Web 服務(wù),不需要構(gòu)建大型的框架,也不需要其它協(xié)議的支持。它的優(yōu)點(diǎn)是能夠使得不同節(jié)點(diǎn)之間文件的傳輸變得非常的簡(jiǎn)單高效,網(wǎng)絡(luò)應(yīng)用程序只需要調(diào)用相應(yīng)的接口就可以很方便地訪問Hessian 所提供的Web 服務(wù)。其處理過程可以描述為:客戶端通過Hessian 本身提供的接口來發(fā)起請(qǐng)求,按照Binary-RPC 協(xié)議將請(qǐng)求信息進(jìn)行填充,填充完畢后根據(jù)自定義的序列化規(guī)則對(duì)請(qǐng)求信息進(jìn)行序列化,將二進(jìn)制格式文件轉(zhuǎn)化為流,通過Http 協(xié)議進(jìn)行傳輸;服務(wù)器端在接收到流后將其返序列化出客戶端調(diào)用的方法和參數(shù),對(duì)服務(wù)端服務(wù)進(jìn)行調(diào)用,然后把處理結(jié)果返回至客戶端。Hessian 協(xié)議框架的完整調(diào)用過程如圖1所示。
圖1 Hessian協(xié)議框架
在Web 應(yīng)用中,大文件上傳是一個(gè)比較重要的交互場(chǎng)景,如上傳較大的Word文檔、Excel表格數(shù)據(jù)、音視頻文件等。傳統(tǒng)的大文件上傳方式主要通過Flash 或ActiveX 來實(shí)現(xiàn),常常因?yàn)槲募萘窟^大或者網(wǎng)絡(luò)異常導(dǎo)致上傳時(shí)間較長(zhǎng)或上傳失敗。隨著HTML 技術(shù)的發(fā)展,萬維網(wǎng)聯(lián)盟(W3C)在2014 年10 月推出HTML 最新標(biāo)準(zhǔn),即HTML5。HTML5 規(guī)范提供了文件上傳、下載、讀取內(nèi)容等接口對(duì)象,如FileList、File、Blob、FileReader、URL。在JavaScript 中,F(xiàn)ile對(duì)象是Blob 對(duì)象的子類,Blob 對(duì)象包含slice 方法,通過這個(gè)方法,就可以對(duì)二進(jìn)制文件進(jìn)行分割切片。
本文采用HTML5 規(guī)范,在客戶端使用slice方法將文件進(jìn)行分割切片傳輸,服務(wù)端自動(dòng)組裝合成原始文件,進(jìn)而實(shí)現(xiàn)大容量文件傳輸功能,同時(shí)能有效提高文件上傳的效率。處理過程簡(jiǎn)單描述為:在客戶端獲取文件的二進(jìn)制內(nèi)容,然后對(duì)其內(nèi)容進(jìn)行拆分,并將每個(gè)切片上傳到服務(wù)端,最終服務(wù)器將文件切片進(jìn)行合并組裝成原始文件。在文件開始上傳之前,客戶端和服務(wù)器端需要有一次信息交互過程,主要包括文件相關(guān)信息以及約定切片的大小,當(dāng)客戶端和服務(wù)器端達(dá)成共識(shí)之后就可以開始文件傳輸。
構(gòu)建基于Hessian 協(xié)議框架的文件傳輸系統(tǒng),需要對(duì)服務(wù)器端和客戶端分別進(jìn)行開發(fā)。服務(wù)器端主要實(shí)現(xiàn)可供客戶端調(diào)用的接口開發(fā)、對(duì)應(yīng)服務(wù)處理函數(shù)的具體實(shí)現(xiàn),以及配置Servlet 發(fā)布Web 應(yīng)用程序??蛻舳酥饕?jiǎng)?chuàng)建與服務(wù)器的連接,訪問服務(wù)器端提供的接口實(shí)現(xiàn)文件傳輸及加工處理等功能。
服務(wù)器端主要實(shí)現(xiàn)將接收到的二進(jìn)制流反序列化為對(duì)服務(wù)的請(qǐng)求,調(diào)用相應(yīng)函數(shù)處理后,將處理結(jié)果序列化為二進(jìn)制流返回給客戶端,不需要開發(fā)用戶界面。
3.1.1 創(chuàng)建Web項(xiàng)目
創(chuàng)建名為FileServer 的Web 項(xiàng)目作為文件傳輸?shù)姆?wù)器端,從Hessian 官網(wǎng)下載最新的hessian.jar文件,存放在WEB-INF/lib 文件夾中,完成服務(wù)器端Hessian協(xié)議的安裝。
3.1.2 設(shè)計(jì)文件傳輸服務(wù)接口
創(chuàng)建文件上傳服務(wù)接口,命名為IFileService,實(shí)現(xiàn)向外界暴露服務(wù)業(yè)務(wù),用于給客戶端調(diào)用。接口中聲明的方法包含了文件的常見操作,比如上傳、下載、重命名、復(fù)制、刪除、文件合并、添加水印等。接口代碼如下:
package fileserver.service;
import java.io.InputStream;
import java.util.Map;
public interface IFileService{
public boolean upload(String filePath,boolean isAppend,InputStream
fileContentStream);
public byte[]download(String filePath,int block-Num);
public boolean rename(String filePath,String old-FileName,String newFileName);
public boolean copyFile(String srcFilePath,String desFilePath);
public boolean delete(String filePath);
public boolean wdMergeAsDoc(String[]wdFilePaths,String pdfFilePath);
public boolean wdAddPicWaterMark(String img-Path,String destFilePath);
}
3.1.3 實(shí)現(xiàn)服務(wù)接口聲明的方法
具體實(shí)現(xiàn)服務(wù)接口中聲明的方法,完成上傳、下載及文件加工處理功能模塊的開發(fā)。以文件上傳功能為例,關(guān)鍵代碼介紹如下:
package fileserver.service.impl;
import fileserver.service.IFileService;
public class FileServiceImpl implements IFileService{
public boolean upload(String filePath,boolean isAppend,InputStream
fileContentStream){
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
boolean bSuccess=false;
try{
bis = new BufferedInputStream(fileContent-Stream);
String fileFullPath = getFileFullPath(sysId,filePath);
String dirPath =fileFullPath.substring(0,file-FullPath.lastIndexO(fFile.separator));
File dirs=new File(dirPath);
i(f!dirs.exists()){
dirs.mkdirs();
}
bos=new BufferedOutputStream(new FileOutput-Stream(fileFullPath,isAppend));
byte[]buffer=new byte[1024];
int r=bis.read(buffer,0,buffer.length);
while(r >0){
bos.write(buffer,0,r);
r=bis.read(buffer,0,buffer.length);
}
}
}
3.1.4 部署服務(wù)器端的服務(wù)
基于Hessian 協(xié)議的Web 服務(wù)以Servlet 方式發(fā)布,因此需要在web.xml 文件中配置相應(yīng)的HessianServlet,同時(shí)還需要配置提供給客戶端調(diào)用的接口以及URL 映射。本文將服務(wù)端應(yīng)用程序部署至Tomcat,啟動(dòng)服務(wù),完成服務(wù)器端的開發(fā)和部署。
客戶端主要將遠(yuǎn)程接口調(diào)用序列化為流,并傳輸?shù)椒?wù)端。為了實(shí)現(xiàn)Hessian 服務(wù)的遠(yuǎn)程調(diào)用,客戶端需要定義與服務(wù)器端一樣的接口類和實(shí)體類,使用Hessian 包的代理工廠類HessianProxyFactory的create方法來實(shí)現(xiàn)調(diào)用。
3.2.1 創(chuàng)建文件上傳客戶端
文件上傳客戶端界面包括操作按鈕和顯示界面。操作按鈕有“上傳”和“刪除”兩個(gè)按鈕,用于選擇需要上傳的文件或刪除已上傳的文件。顯示界面用于顯示選擇的文件名稱、文件大小、上傳進(jìn)度等信息,如圖2所示。
圖2 文件上傳客戶端
3.2.2 調(diào)用遠(yuǎn)程服務(wù)上傳文件
客戶端添加對(duì)Hessian.jar文件的引用,同時(shí)將服務(wù)器端的FileServer 接口打包成jar文件提供給客戶端調(diào)用。創(chuàng)建HessianProxyFactory 實(shí)例,用于獲得Hessian 服務(wù)的遠(yuǎn)程調(diào)用,選擇需要上傳的文件,上傳至文件服務(wù)器,關(guān)鍵代碼如下所示:
public class FileClientHandler{
private IFileService fileService;
public FileClientHandler(){
ini(t);
}
public void ini(t){
HessianProxyFactory factory = new HessianProxy-Factory();
try{
String[]str=getServerPro();
fileService =(IFileService)factory.create(IFileService.class,systemId=st[r1];
}catch(MalformedURLException e){
e.printStackTrace();
}
}
本文設(shè)計(jì)并實(shí)現(xiàn)了與具體網(wǎng)絡(luò)應(yīng)用相互獨(dú)立的文件傳輸服務(wù)系統(tǒng),供不同的應(yīng)用程序進(jìn)行調(diào)用,節(jié)約了外部網(wǎng)絡(luò)應(yīng)用的開發(fā)成本。系統(tǒng)基于Hessian 協(xié)議框架和HTML5 標(biāo)準(zhǔn)開發(fā),突破了文件上傳的各種限制,能有效減少傳輸開銷、提升文件傳輸效率,保證文件傳輸?shù)姆€(wěn)定性和可靠性。后續(xù)的研究工作中,還可以繼續(xù)優(yōu)化和創(chuàng)新文件傳輸?shù)倪壿?,以提供更高效和可靠的文件傳輸服?wù)。