昨天,(在我的上一篇博客中)寫了通過瀏覽器上傳圖片到服務器(php),今天將這個功能付諸實踐.(還完善了服務端的代碼)
不試不知道,原來通過android 向服務端發送圖片還真是挺麻煩的一件事.
上傳代碼:
/* 上傳文件至Server的方法 */ private void uploadFile() { String end = "\r\n"; String twoHyphens = "--"; String boundary = "*****"; try { URL url = new URL(postUrl); HttpURLConnection con = (HttpURLConnection) url.openConnection(); /* Output to the connection. Default is false, set to true because post method must write something to the connection */ con.setDoOutput(true); /* Read from the connection. Default is true.*/ con.setDoInput(true); /* Post cannot use caches */ con.setUseCaches(false); /* Set the post method. Default is GET*/ con.setRequestMethod("POST"); /* 設置請求屬性 */ con.setRequestProperty("Connection", "Keep-Alive"); con.setRequestProperty("Charset", "UTF-8"); con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); /*設置StrictMode 否則HTTPURLConnection連接失敗,因為這是在主進程中進行網絡連接*/ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build()); /* 設置DataOutputStream,getOutputStream中默認調用connect()*/ DataOutputStream ds = new DataOutputStream(con.getOutputStream()); //output to the connection ds.writeBytes(twoHyphens + boundary + end); ds.writeBytes("Content-Disposition: form-data; " + "name=\"file\";filename=\"" + fileName + "\"" + end); ds.writeBytes(end); /* 取得文件的FileInputStream */ FileInputStream fStream = new FileInputStream(uploadFile); /* 設置每次寫入8192bytes */ int bufferSize = 8192; byte[] buffer = new byte[bufferSize]; //8k int length = -1; /* 從文件讀取數據至緩沖區 */ while ((length = fStream.read(buffer)) != -1) { /* 將資料寫入DataOutputStream中 */ ds.write(buffer, 0, length); } ds.writeBytes(end); ds.writeBytes(twoHyphens + boundary + twoHyphens + end); /* 關閉流,寫入的東西自動生成Http正文*/ fStream.close(); /* 關閉DataOutputStream */ ds.close(); /* 從返回的輸入流讀取響應信息 */ InputStream is = con.getInputStream(); //input from the connection 正式建立HTTP連接 int ch; StringBuffer b = new StringBuffer(); while ((ch = is.read()) != -1) { b.append((char) ch); } /* 顯示網頁響應內容 */ // Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功 System.out.println(b.toString()); } catch (Exception e) { /* 顯示異常信息 */ // Toast.makeText(MainActivity.this, "Fail:" + e, Toast.LENGTH_SHORT).show();//Post失敗 System.out.println(e); } }
上篇博文有說上傳圖片必須使用POST方法,這里當然使用的就是post方法.這里上傳跟普通上傳寫法沒啥變化.
不過我還是不習慣使用這個方法(我一直使用volley框架, 有興趣可以百度一下.一個官方推出的很好用的框架,要不是需要用到傳圖我還不會研究這個寫法)
使用原生POST方法的基本步驟:
1.使用 HttpURLConnection 建立連接
2.設置請求屬性
3.根據請求格式組裝參數(很麻煩 , 可以通過瀏覽器發送POST請求,取出調試信息對比)
4.建立輸入流,並寫入數據(FileInputStream 和下面循環寫入哪里)
5.獲取返回流,並處理返回參數
6.關閉所有流
該部分代碼幾乎完全借鑒大神的寫法.里面注釋也很多我也不多說了.
值得一提的是在4.0(android 版本)以后就已經不支持在主線程中執行上傳,下載等耗時操作了.
這也很合理,假如你在上傳文件的時候,突然你的網絡不好,你就會一直在上傳狀態.體驗很不好.
所以調用上面的方法需要新建一個線程:
new Thread(new Runnable() { @Override public void run() { uploadFile(); } }).start();
這個調用方法是在上傳方法與該方法同文件時可以這樣寫,如果上傳方法在獨立的class文件中需要先實例化然后通過
實例化對象名.uploadFile();
的方法調用.
服務器端
上篇博文里面只是簡單的實現了,接收並轉存圖片.這里對該服務端進行完善:
<?php /** * 接收上傳的圖片 * * ------------ * 200 ok * 401 Error method * 500 Internal error * ------------ */ // ini_set("display_errors", "On"); // error_reporting(E_ALL | E_STRICT); header('Access-Control-Allow-Origin: *'); // 解決前段javascript跨域請求 $fileInfo = $_FILES['file']; $maxSize=2097152;//允許的最大值 $allowExt=array('jpeg','jpg','png','gif','wbmp'); $flag=true;//檢測是否為真實圖片類型 if($fileInfo['error']==0){ //判斷上傳文件的大小 if($fileInfo['size']>$maxSize){ $data = '上傳文件過大'; return Response::show(201,'error1', $data); exit(); } //$ext=strtolower(end(explode('.',$fileInfo['name'])));獲取后綴 $ext=pathinfo($fileInfo['name'],PATHINFO_EXTENSION); if(!in_array($ext,$allowExt)){ $data = '非法文件類型'; return Response::show(202 , 'error2' , $data); exit(); } //判斷文件是否是通過HTTP POST方式上傳來的 if(!is_uploaded_file($fileInfo['tmp_name'])){ $data = '文件不是通過HTTP POST方式上傳來的'; return Response::show(203 , 'error3' , $data); exit(); } //檢測是否為真實的圖片類型 if($flag){ if(!getimagesize($fileInfo['tmp_name'])){ $data = '不是真正圖片類型'; return Response::show(204 , 'error4' , $data); exit(); } } //創建與id對應的文件夾 $id = $_GET['id']; if(!file_exists($id)){ mkdir('../files/'.$id); //chmod($id , 0777); } if(@move_uploaded_file($fileInfo['tmp_name'],'../files/'.$id.'/'.$fileInfo['name'])){ $data = '文件上傳成功'; return Response::show(200 , 'ok' , $data); }else{ $data = '文件上傳失敗'; return Response::show(404 , 'error5' , $data); } }else{ switch($fileinfo['error']){ case 1: $data = '上傳文件超過了PHP配置文件中upload_max_filesize選項的值'; return Response::show(401 , 'error5' , $data); break; case 2: $data = '超過了表單MAX_FILE_SIZE限制的大小'; return Response::show(402 , 'error5' , $data); break; case 3: $data = '文件部分被上傳'; return Response::show(403 , 'error5' , $data); break; case 4: $data = '沒有選擇上傳文件'; return Response::show(405 , 'error5' , $data); break; case 6: $data = '沒有找到臨時目錄'; return Response::show(405 , 'error5' , $data); break; case 7: case 8: $data = '系統錯誤'; return Response::show(405 , 'error5' , $data); break; } }
這里對圖片進行了各種檢測.比昨天的更可靠了是吧.還統一了返回的json格式方便客戶端進行解析.(還有就是,上面的服務端的代碼也是借鑒了慕課大神的寫法,略作修改)
