通過android 客戶端上傳圖片到服務器


昨天,(在我的上一篇博客中)寫了通過瀏覽器上傳圖片到服務器(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格式方便客戶端進行解析.(還有就是,上面的服務端的代碼也是借鑒了慕課大神的寫法,略作修改)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM