struts2中通過Action以InputStream的下載文件以及在iOS以及Android端接收的實現方式

struts2中通過Action以InputStream的下載文件以及在iOS以及Android端接收的實現方式

最近在移動開發中遇到了一些文件下載的問題,實現後特地記錄一下,以備以後查閱。

最簡單的下載的實現方式是將文件的在網絡上的URL直接發送給手機,然後手機通過URL來請求這個文件,這麼做有個缺點無法對請求的用戶進行準確的驗證。另一種方法是通過Action先對用戶的身份驗證通過後再發送文件給手持設備(請求端)。下面就來實現第二中方式。

 

  • 服務器端非常簡單,就是寫個xml的配置文件,和實現一個簡單的action即可。

struts.xml的配置文件如下:

複製代碼
<result name="download" type="stream">
  <param name="contentType">application/octet-stream</param>
  <param name="inputName">targetFile</param>
  <param name="contentDisposition">${suffix}</param>
  <param name="contentLength">${fileSize}</param>
  <param name="bufferSize">4096</param>
</result>
複製代碼

說明:

contentType:指定文件的類型,application/octet-stream代表所有的文件類型,查看其他的文件類型描述;
inputName:文件的InputStream流,action中需要提供一個返回InputStream的getTargetFile()方法;

contentDisposition:下載文件的文件名,${suffix}指到action中獲取getSuffix()方法的返回值;也可以在這裏放置filename=${fileName},這樣通過瀏覽器訪問的時候瀏覽器會自動查找到文件名,並顯示出來;
contentLength:下載的當前文件的大小,獲取方式同上,類型是long
bufferSize:緩存的大小

action對象實現如下:
/**
     * 文件的輸出流
     * @return
     * @throws Exception
     */
    public InputStream getTargetFile() throws Exception {
        java.io.File f = new java.io.File("D:\\test.avi");
        if (f.exists()) {
            return new FileInputStream(f);
        } else {
            return null;
        }
    }
      
    /**
     * 設置返回的文件的名字
     * @return
     */
    public String getFileName() {
        return "test.avi";
    }
      
    /**
     * 設置返回的文件的大小
     * @return
     */
    public long getFileSize() {
        java.io.File f = new java.io.File("D:\\test.avi");
        return f.length();
    }
      
    /**
     * 執行請求的邏輯處理,然後根據結果來判斷是否返回文件
     * @return
     */
    public String download() {
       //進行認證或其它的邏輯檢查
        if(true){
            return "download";
        }
        return "error";
    }
  •  移動請求端實現如下:

    iOS端

網絡訪問端代碼如下:

NSURL *downloadURL = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:downloadURL];
NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *resData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(error)
{
      NSLog(@"請求下載文件失敗,錯誤信息:%@",error);
      return nil;
}
if(resData)
{
     if(response && [response respondsToSelector:@selector(allHeaderFields)])
   {
          NSDictionary *httpResponseHeaderFields = [response allHeaderFields];//獲得相應的頭
          long size = [[httpResponseHeaderFields objectForKey:@"Content-Length"] longLongValue];//獲得文件的大小,是由服務器在相應頭中傳遞過來的
          NSString *fileSuffix = [httpResponseHeaderFields objectForKey:@"Content-Disposition"];//我在的服務器端設置的存放後綴名
          VSFileUtil *fileUtil = [[VSFileUtil alloc]init];//自定義的一個文件工具類
          NSString *filePath = [fileUtil writeToFileWithNSData:resData FileName:[fileId stringByAppendingFormat:@".%@",fileSuffix]];//創建文件
          return filePath;
      }
}

    文件工具類的代碼如下:

NSArray *dir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);//獲得Library/Caches目錄,該目錄程序退出不會清空,iTunes也不備份此目錄
NSString *cDownloadBaseFolderPath = [[dir objectAtIndex:0] stringByAppendingPathComponent:@"FMADownload"];//創建Library/Caches/FMADownload目錄作爲下載目錄
NSString *filePath = [cDownloadBaseFolderPath stringByAppendingPathComponent:file];//根據文件名和路徑構建出文件的絕對路徑
NSFileManager *fm = [NSFileManager defaultManager];//獲取文件管理器
[fm removeItemAtPath:filePath error:nil];//如果文件已經存在則移除該文件,文件不存在時也不會拋出異常,如果想捕獲提示信息,可以定義一個NSError傳遞給error參數即可
if([data writeToFile:filePath atomically:YES])//以原子處理的方式將內容寫進文件中
{
   return filePath;
}
else
{
   return nil;
}

 

    Android端

    這個由於是java開發的,這個過程將變得比iOS上簡單n倍,具體代碼如下:

 

public void download() throws Exception {
	InputStream is = null;
	BufferedInputStream bis = null;
	FileOutputStream fos = null;
	BufferedOutputStream bos = null;
	try {
		httpClient = new DefaultHttpClient(new BasicHttpParams());
		HttpPost httpRequest = new HttpPost(validateURL);//validateURL是的請求地址
		HttpResponse response = httpClient.execute(httpRequest);
		Header[] headers = response.getAllHeaders();
		long size = 0;//文件大小
		String suff = "";//文件後綴名
		for(Header h : headers) {
			if("Content-Disposition".equals(h.getName())) {
				suff = h.getValue();
				Log.i("janken", suff);
			} else if ("Content-Length".equals(h.getName())) {
				size = Long.valueOf(h.getValue());
				Log.i("janken", size + "");
			}
		}
		if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
			throw new Exception("請求失敗");
		}
		HttpEntity resEntity = response.getEntity();
		is = resEntity.getContent();//獲得文件的輸入流
		bis = new BufferedInputStream(is);
		File newFile = new File("/sdcard/test." + suff);
		fos = new FileOutputStream(newFile);
		bos = new BufferedOutputStream(fos);
			
		byte[] bytes = new byte[4096];
		int len = 0;//最後一次的長度可能不足4096
		while((len = bis.read(bytes)) > 0) {
			bos.write(bytes,0,len);
		}
		bos.flush();
	} finally {
		if(bis != null)bis.close();
		if(bos != null)bos.close();
		if(fos != null)fos.close();
		httpClient.getConnectionManager().shutdown();
	}
}

 

  

 轉自:http://www.cnblogs.com/janken/archive/2012/06/06/2534977.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章