Android端通過HttpURLConnection上傳文件到服務器

atts 8年前發布 | 2K 次閱讀 Java dnf翻牌機_翻牌機游戲

Android端通過HttpURLConnection上傳文件到服務器

一:實現原理

最近在做Android客戶端的應用開發,涉及到要把圖片上傳到后臺服務器中,自己選擇了做Spring3 MVC HTTP API作為后臺上傳接口,android客戶端我選擇用HttpURLConnection來通過form提交文件數據實現上傳功能,本來想網上搜搜拷貝一下改改代碼就好啦,發現根本沒有現成的例子,多數的例子都是基于HttpClient的或者是基于Base64編碼以后作為字符串來傳輸圖像數據,于是我不得不自己動手,參考了網上一些資料,最終實現基于HttpURLConnection上傳文件的android客戶端代碼,廢話少說,其實基于HttpURLConnection實現文件上傳最關鍵的在于要熟悉Http協議相關知識,知道MIME文件塊在Http協議中的格式表示,基本的傳輸數據格式如下:


其中boundary表示form的邊界,只要按照格式把內容字節數寫到HttpURLConnection的對象輸出流中,服務器端的Spring Controller 就會自動響應接受,跟從瀏覽器頁面上上傳文件是一樣的。

服務器端HTTP API, 我是基于Spring3 MVC實現的Controller,代碼如下:
@RequestMapping(value = "/uploadMyImage/{token}", method = RequestMethod.POST)
public @ResponseBody String getUploadFile(HttpServletRequest request, HttpServletResponse response,
        @PathVariable String token) {
    logger.info("spring3 MVC upload file with Multipart form");
    logger.info("servlet context path : " + request.getSession().getServletContext().getRealPath("/"));
    UserDto profileDto = userService.getUserByToken(token);
    String imgUUID = "";
    try {
        if (request instanceof MultipartHttpServletRequest && profileDto.getToken() != null) {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            logger.info("spring3 MVC upload file with Multipart form");
            // does not work, oh my god!!
            MultipartFile file = multipartRequest.getFiles("myfile").get(0);
            InputStream input = file.getInputStream();
            long fileSize = file.getSize();
            BufferedImage image = ImageIO.read(input);
            // create data transfer object
            ImageDto dto = new ImageDto();
            dto.setCreateDate(new Date());
            dto.setFileName(file.getOriginalFilename());
            dto.setImage(image);
            dto.setCreator(profileDto.getUserName());
            dto.setFileSize(fileSize);
            dto.setType(ImageAttachmentType.CLIENT_TYPE.getTitle());
            dto.setUuid(UUID.randomUUID().toString());

            /// save to DB
            imgUUID = imageService.createImage(dto);
            input.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
        logger.error("upload image error", e);
    }

    return imgUUID;
}

Android客戶端基于HttpURLConnection實現上傳的代碼,我把它封裝成一個單獨的類文件,這樣大家可以直接使用,只要傳入上傳的URL等參數即可。代碼如下:

package com.demo.http;

import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;

import android.os.Handler;
import android.util.Base64;
import android.util.Log;

public class UploadImageTask implements APIURLConstants {
    private String requestURL = DOMAIN_ADDRESS + UPLOAD_DESIGN_IMAGE_URL; // default
    private final String CRLF = "\r\n";
    private Handler handler;
    private String token;
    public UploadImageTask(String token, Handler handler) {
        this.handler = handler;
        this.token = token;
    }

    public String execute(File...files) {
        InputStream inputStream = null;
        HttpURLConnection urlConnection = null;
        FileInputStream fileInput = null;
        DataOutputStream requestStream = null;
        handler.sendEmptyMessage(50);
        try {
            // open connection
            URL url = new URL(requestURL.replace("{token}", this.token));
            urlConnection = (HttpURLConnection) url.openConnection();
            // create random boundary
            Random random = new Random();
            byte[] randomBytes = new byte[16];
            random.nextBytes(randomBytes);
            String boundary = Base64.encodeToString(randomBytes, Base64.NO_WRAP);

            /* for POST request */
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.setRequestMethod("POST");
            long size = (files[0].length() / 1024);
            if(size >= 1000) {
                handler.sendEmptyMessage(-150);
                return "error";
            }
            // 構建Entity form
            urlConnection.setRequestProperty("Connection", "Keep-Alive");
            urlConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            urlConnection.setRequestProperty("Cache-Control", "no-cache");

            // never try to chunked mode, you need to set a lot of things
            //  if(size > 400) {
            //      urlConnection.setChunkedStreamingMode(0);
            //  }
            //  else {
            //      urlConnection.setFixedLengthStreamingMode((int)files[0].length());
            //  }
            // end comment by zhigang on 2016-01-19

            /* upload file stream */
            fileInput = new FileInputStream(files[0]);
            requestStream = new DataOutputStream(urlConnection.getOutputStream());
            String nikeName = "myfile";
            requestStream = new DataOutputStream(urlConnection.getOutputStream());
            requestStream.writeBytes("--" + boundary + CRLF);
            requestStream.writeBytes("Content-Disposition: form-data; name=\"" + nikeName + "\"; filename=\"" + files[0].getName() + "\""+ CRLF);
            requestStream.writeBytes("Content-Type: " + getMIMEType(files[0]) + CRLF);
            requestStream.writeBytes(CRLF);
            // 寫圖像字節內容
            int bytesRead;
            byte[] buffer = new byte[8192];
            handler.sendEmptyMessage(50);
            while((bytesRead = fileInput.read(buffer)) != -1) {
                requestStream.write(buffer, 0, bytesRead);
            }
            requestStream.flush();
            requestStream.writeBytes(CRLF);
            requestStream.flush();
            requestStream.writeBytes("--" + boundary + "--" + CRLF);
            requestStream.flush();
            fileInput.close();

            // try to get response
            int statusCode = urlConnection.getResponseCode();
            if (statusCode == 200) {
                inputStream = new BufferedInputStream(urlConnection.getInputStream());
                String imageuuId = HttpUtil.convertInputStreamToString(inputStream);
                Log.i("image-uuid", "uploaded image uuid : " + imageuuId);
                handler.sendEmptyMessage(50);
                return imageuuId;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(requestStream != null) {
                try {
                    requestStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fileInput != null) {
                try {
                    fileInput.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
        handler.sendEmptyMessage(50);
        return null;
    }

    private String getMIMEType(File file) {
        String fileName = file.getName();
        if(fileName.endsWith("png") || fileName.endsWith("PNG")) {
            return "image/png";
        }
        else {
            return "image/jpg";
        }
    }

}
經過本人測試,效果杠杠的!!所以請忘記HttpClient這個東西,android開發再也不需要它了。


 本文由用戶 atts 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!