本文是上一篇文章 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.MultipartForm if 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.Filename file, err := v.Open() checkErrorV2(err, "Open file error."+fileName) defer file.Close() outputFilePath := "/home/admin/桌面/" + fileName writer, 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是一个简单的检查错误的函数。
有疑问加站长微信联系(非本文作者)