標籤:android上傳資料到網路 http協議
首先我們需要使用HTTP協議發送資料,我們就要知道HTTP發送上傳檔案到伺服器的時候需要哪些頭欄位已經相關的配置,請看
這是使用瀏覽器類比上傳檔案到伺服器時候所發送的請求,我們可以看到它包含了要求標頭欄位和實體部分,但是多了一個---------------------------7da2137580612,它實際上是一條分隔線,用於分隔實體資料的,他在使用分隔實體資料的時候會在前麵包含多兩個"-"而在結束的時候會在除了在前面都出兩個減號"-"之外,還會在末尾都出兩個減號"-"表示結束。初次之外,在Content-Type這個頭欄位當中,大家可以看到他的頭欄位是"multipart/form-data",因為只有當Content-Type頭欄位設定為該值的時候,伺服器才會接受檔案並且儲存下來。然後他的組成依次是:要求標頭欄位+兩個斷行符號換行(\r\n),然後是分隔線(記得加上兩個減號)之後是一個斷行符號換行(\r\n),之後兩個斷行符號換行,到資料值,之後是分隔線,這樣依次下去
實現該功能的大概思路:因為是有關於網路的操作,不能直接在UI線程中執行,所以開一條線程去完成上傳功能(關於斷點上傳以後再與大家分享)。然後線程一定需要注意的時候需要添加一個屬於該線程的Looper,不然程式會崩潰掉。然後在MVC中的C層去控制下載。下載代碼過程主要是難在如何組拼請求資料,最難的水Content-Length這個頭欄位的值。但是可以通過Content-Length=文本+檔案,就可以算出他的值。
下面是具體代碼實現:
MainActivity.java,他的主要功能是提供一個介面,然後有一個按鈕和三個輸入架構,點擊按鈕之後就可以上傳檔案,當檔案位於SD卡根目錄而且存在的時候則上傳,否則只是上傳title和length。他開了一條子線程去完成上傳的任務。該類主要有四個方法,分別是
1,public static boolean save(String title, String length),對於需要上傳檔案不存在但是可以上傳title和length
2,public static boolean save(String title, String length, File uploadFile),用於上傳的檔案存在的時候則是調用該方法上傳
3,private static boolean sendHttpClientPOSTRequest(String path, Map<String, String> params, String encoding)用於發送GET或者POST請求,被第一個save方法調用
4,public static boolean post(String path, Map<String, String> params, FormFile[] files)用於上傳檔案,被第二個save方法調用。
public class MainActivity extends Activity{/* 上傳檔案標題 */private EditText titleText;/* 上傳的長度 */private EditText lengthText;/* 上傳的檔案名稱 */private EditText nameText;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);titleText = (EditText) this.findViewById(R.id.title);lengthText = (EditText) this.findViewById(R.id.timelength);nameText = (EditText) this.findViewById(R.id.filename);}/** * 點擊儲存按鈕之後使用者將會上傳檔案 * @param v 按鈕 */public void save(View v){String filename = nameText.getText().toString();String title = titleText.getText().toString();String length = lengthText.getText().toString();UploadThread uploadThread = new UploadThread(filename, title, length, this);uploadThread.start();}}@SuppressLint("ShowToast")class UploadThread extends Thread{String filename;String title;String length;Context context;public UploadThread (String filename , String title , String length , Context context){super();this.filename = filename;this.title = title;this.length = length;this.context = context;}@Overridepublic void run(){/* * 檢測SD卡的情況,MEDIA_MOUNTED表明sd對象是存在並具有讀/寫入權限 * MEDIA_MOUNTED_READ_ONLY表明SD卡唯讀 */Looper.prepare();if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) || Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY)){File uploadFile = new File(Environment.getExternalStorageDirectory(), filename);// 位於根目錄下面,檔案名稱是filenameif (uploadFile.exists()){boolean result = NewsService.save(title, length, uploadFile);// 假如檔案存在則上傳,包括title,length已經fileif (result){Toast.makeText(context, R.string.success, 1).show();} else{Toast.makeText(context, R.string.error, 1).show();}} else{Toast.makeText(context, R.string.filenoexsit, 1).show();}} else{boolean result = NewsService.save(title, length);//假如檔案不存在,則只是上傳title和lengthif (result){Toast.makeText(context, R.string.success, 1).show();} else{Toast.makeText(context, R.string.error, 1).show();}}Looper.loop();}}Service類
public class NewsService {/** * 儲存資料 這是當沒有上傳成功的時候調用 * @param title 標題 * @param length 時間長度 * @return */public static boolean save(String title, String length) {String path = "http://192.168.0.168:8080/web/ManageServlet";Map<String, String> params = new HashMap<String, String>();params.put("title", title);params.put("timelength", length);try {return sendHttpClientPOSTRequest(path, params, "UTF-8");} catch (Exception e) {e.printStackTrace();}return false;}/** * 通過HttpClient發送Post請求 也可以直接使用GET或者POST發送請求 * @param path 請求路徑 * @param params 請求參數 * @param encoding 編碼 * @return 請求是否成功 */private static boolean sendHttpClientPOSTRequest(String path, Map<String, String> params, String encoding) throws Exception{List<NameValuePair> pairs = new ArrayList<NameValuePair>();//存放請求參數if(params!=null && !params.isEmpty()){for(Map.Entry<String, String> entry : params.entrySet()){pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}}UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, encoding);HttpPost httpPost = new HttpPost(path);httpPost.setEntity(entity);DefaultHttpClient client = new DefaultHttpClient();HttpResponse response = client.execute(httpPost);if(response.getStatusLine().getStatusCode() == 200){return true;}return false;}/** * 上傳檔案 * @param title 檔案名稱 * @param length 長度 * @param uploadFile 檔案 * @return */public static boolean save(String title, String length, File uploadFile) {String path = "http://192.168.1.125:8080/web/ManagerServlet";Map<String, String> params = new HashMap<String, String>();params.put("title", title);params.put("timelength", length);FormFile formFile = new FormFile(uploadFile, "videofile", "image/gif");//指定上傳檔案的類型try {return post(path, params, new FormFile[]{ formFile});} catch (Exception e) {e.printStackTrace();}return false;}/** * 真正實現上傳檔案的類 * @param path 上傳路徑,即是伺服器的路徑,可以是網域名稱 * @param params 請求參數 key為參數名,value為參數值 * @param file[] 上傳檔案,可以是多個 */<pre name="code" class="java"> public static boolean post(String path, Map<String, String> params, FormFile[] files) {final String BOUNDARY = "---------------------------7da2137580612"; // 資料分隔線final String endline = "--" + BOUNDARY + "--\r\n";// 資料結束標誌,後麵包含一個斷行符號分行符號號int fileDataLength = 0;for (FormFile uploadFile : files){// 得到檔案file類型資料的總長度,加入當同事上傳多個檔案的時候,需要使用到迭代,每一次迭代算出的是一個檔案的Http長度StringBuilder fileExplain = new StringBuilder();fileExplain.append("--");fileExplain.append(BOUNDARY);fileExplain.append("\r\n");// Content-Disposition這個頭欄位是用於設定當使用者不能取得正確的檔案名稱的時候的預設名稱,有時候也會死從伺服器返回給使用者,這時候使用者從伺服器下載資料但是取得檔案名稱失敗的時候也會使用這個作為檔案的預設名稱fileExplain.append("Content-Disposition: form-data;name=\"" + uploadFile.getParameterName() + "\";filename=\"" + uploadFile.getFilname() + "\"\r\n");fileExplain.append("Content-Type: " + uploadFile.getContentType() + "\r\n\r\n");fileDataLength += fileExplain.length();if (uploadFile.getInStream() != null){fileDataLength += uploadFile.getFile().length();} else{fileDataLength += uploadFile.getData().length;}fileDataLength += "\r\n".length();}StringBuilder textEntity = new StringBuilder();for (Map.Entry<String, String> entry : params.entrySet()){// 構造文本型別參數的實體資料textEntity.append("--");textEntity.append(BOUNDARY);textEntity.append("\r\n");textEntity.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");textEntity.append(entry.getValue());textEntity.append("\r\n");}// 計算傳輸給伺服器的實體資料總長度int dataLength = textEntity.toString().getBytes().length + fileDataLength + endline.getBytes().length;Socket socket = null;OutputStream outStream = null;BufferedReader reader = null;try{URL url = new URL(path);int port = url.getPort() == -1 ? 80 : url.getPort();socket = new Socket(InetAddress.getByName(url.getHost()), port);outStream = socket.getOutputStream();// 下面完成HTTP要求標頭的發送String requestmethod = "POST " + url.getPath() + " HTTP/1.1\r\n";outStream.write(requestmethod.getBytes());String accept = "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\n";outStream.write(accept.getBytes());String language = "Accept-Language: zh-CN\r\n";outStream.write(language.getBytes());String contenttype = "Content-Type: multipart/form-data; boundary=" + BOUNDARY + "\r\n";outStream.write(contenttype.getBytes());String contentlength = "Content-Length: " + dataLength + "\r\n";outStream.write(contentlength.getBytes());String alive = "Connection: Keep-Alive\r\n";outStream.write(alive.getBytes());String host = "Host: " + url.getHost() + ":" + port + "\r\n";outStream.write(host.getBytes());// 寫完HTTP要求標頭後根據HTTP協議再寫一個斷行符號換行outStream.write("\r\n".getBytes());// 把所有文本類型的實體資料發送出來outStream.write(textEntity.toString().getBytes());// 把所有檔案類型的實體資料發送出來for (FormFile uploadFile : files){StringBuilder fileEntity = new StringBuilder();fileEntity.append("--");fileEntity.append(BOUNDARY);fileEntity.append("\r\n");fileEntity.append("Content-Disposition: form-data;name=\"" + uploadFile.getParameterName() + "\";filename=\"" + uploadFile.getFilname() + "\"\r\n");fileEntity.append("Content-Type: " + uploadFile.getContentType() + "\r\n\r\n");outStream.write(fileEntity.toString().getBytes());if (uploadFile.getInStream() != null){byte[] buffer = new byte[1024];int len = 0;while ((len = uploadFile.getInStream().read(buffer, 0, 1024)) != -1){outStream.write(buffer, 0, len);}uploadFile.getInStream().close();} else{outStream.write(uploadFile.getData(), 0, uploadFile.getData().length);}outStream.write("\r\n".getBytes());}// 下面發送資料結束標誌,表示資料已經結束outStream.write(endline.getBytes());reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));if (reader.readLine().indexOf("200") == -1){// 讀取web伺服器返回的資料,判斷請求碼是否為200,如果不是200,代表請求失敗return false;}outStream.flush();} catch (MalformedURLException e){e.printStackTrace();} catch (UnknownHostException e){e.printStackTrace();} catch (IOException e){e.printStackTrace();}finally{try{outStream.close();} catch (IOException e){e.printStackTrace();}try{reader.close();} catch (IOException e){e.printStackTrace();}try{socket.close();} catch (IOException e){e.printStackTrace();}}return true;}
}
這樣檔案的上傳功能就可以實現了。
Android中利用HTTP協議實現上傳檔案到伺服器