本文是上一篇文章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,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;
- }
注:checkErrorV2是一个简单的检查错误的函数。
- //客户端上传多个文件,并带有请求参数
- 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))
- }