Golang+Android實現檔案上傳(多檔案上傳、附帶請求參數),golangandroid
本文是上一篇文章 Golang+Android(使用HttpURLConnection)實現檔案上傳 的升級版,實現多檔案上傳功能,並且附帶http請求參數。
用戶端代碼:
/** * 使用HttpURLConnection通過POST方式提交請求,並上傳檔案。 * * @param actionUrl 訪問的url * @param textParams 文本類型的POST參數(key:value) * @param filePaths 檔案路徑的集合 * @return 伺服器返回的資料,出現異常時返回 null */ public static String postWithFiles(String actionUrl, Map<String, String> textParams, List<String> filePaths) { try { final String BOUNDARY = UUID.randomUUID().toString(); final String PREFIX = "--"; final String LINE_END = "\r\n"; final String MULTIPART_FROM_DATA = "multipart/form-data"; final String CHARSET = "UTF-8"; URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); //緩衝大小 conn.setChunkedStreamingMode(1024 * 64); //逾時 conn.setReadTimeout(5 * 1000); conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); // 拼接文本類型的參數 StringBuilder textSb = new StringBuilder(); if (textParams != null) { for (Map.Entry<String, String> entry : textParams.entrySet()) { textSb.append(PREFIX).append(BOUNDARY).append(LINE_END); textSb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINE_END); textSb.append("Content-Type: text/plain; charset=" + CHARSET + LINE_END); textSb.append("Content-Transfer-Encoding: 8bit" + LINE_END); textSb.append(LINE_END); textSb.append(entry.getValue()); textSb.append(LINE_END); } } DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); outStream.write(textSb.toString().getBytes()); //參數POST方式 //outStream.write("userId=1&cityId=26".getBytes()); // 傳送檔案資料 if (filePaths != null) { for (String file : filePaths) { StringBuilder fileSb = new StringBuilder(); fileSb.append(PREFIX).append(BOUNDARY).append(LINE_END); fileSb.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.substring(file.lastIndexOf("/") + 1) + "\"" + LINE_END); fileSb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END); fileSb.append(LINE_END); outStream.write(fileSb.toString().getBytes()); InputStream is = new FileInputStream(file); byte[] buffer = new byte[1024 * 8]; int len; while ((len = is.read(buffer)) != -1) { outStream.write(buffer, 0, len); } is.close(); outStream.write(LINE_END.getBytes()); } } // 請求結束標誌 outStream.write((PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes()); outStream.flush(); // 得到響應碼 int responseCode = conn.getResponseCode(); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), CHARSET)); StringBuilder resultSb = null; String line; if (responseCode == 200) { resultSb = new StringBuilder(); while ((line = br.readLine()) != null) { resultSb.append(line).append("\n"); } } br.close(); outStream.close(); conn.disconnect(); return resultSb == null ? null : resultSb.toString(); } catch (IOException e) { e.printStackTrace(); } return null; }伺服器端代碼:
//用戶端上傳多個檔案,並帶有請求參數func handleUploadFile(w http.ResponseWriter, r *http.Request) {fmt.Println("client:", r.RemoteAddr, "method:", r.Method)r.ParseForm()r.ParseMultipartForm(32 << 20) //最大記憶體為32M//讀取參數userId := r.FormValue("userId")cityId := r.FormValue("cityId")log.Println("userId=", userId, "cityId=", cityId)mp := r.MultipartFormif mp == nil {log.Println("not MultipartForm.")w.Write(([]byte)("不是MultipartForm格式"))return}fileHeaders, findFile := mp.File["file"]if !findFile || len(fileHeaders) == 0 {log.Println("file count == 0.")w.Write(([]byte)("沒有上傳檔案"))return}for _, v := range fileHeaders {fileName := v.Filenamefile, err := v.Open()checkErrorV2(err, "Open file error."+fileName)defer file.Close()outputFilePath := "/home/admin/案頭/" + fileNamewriter, err := os.OpenFile(outputFilePath, os.O_WRONLY|os.O_CREATE, 0666)checkErrorV2(err, "Open local file error")io.Copy(writer, file)}msg := fmt.Sprintf("成功上傳了%d個檔案", len(fileHeaders))w.Write(([]byte)(msg))}註:checkErrorV2是一個簡單的檢查錯誤的函數。