Android端通过HttpURLConnection上传文件到服务器

简介: Android端通过HttpURLConnection上传文件到服务器

Android端通过HttpURLConnection上传文件到服务器


一:实现原理


最近在做Android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做Spring3 MVC HTTP API作为后台上传接口,android客户端我选择用HttpURLConnection来通过form提交文件数据实现上传功能,本来想网上搜搜拷贝一下改改代码就好啦,发现根本没有现成的例子,多数的例子都是基于HttpClient的或者是基于Base64编码以后作为字符串来传输图像数据,于是我不得不自己动手,参考了网上一些资料,最终实现基于HttpURLConnection上传文件的android客户端代码,废话少说,其实基于HttpURLConnection实现文件上传最关键的在于要熟悉Http协议相关知识,知道MIME文件块在Http协议中的格式表示,基本的传输数据格式如下:


20160122202047690.png


其中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开发再也不需要它了。


相关文章
|
6月前
|
PHP Android开发
android通过http上传文件,服务器端用php写(原创)
android通过http上传文件,服务器端用php写(原创)
62 4
|
1月前
SecureCRT 通过xftp命令行上传文件到服务器上
SecureCRT 通过xftp命令行上传文件到服务器上
97 1
|
6月前
|
JSON Android开发 数据格式
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
android与Web服务器交互时的cookie使用-兼谈大众点评数据获得(原创)
84 2
|
6月前
|
监控 Unix 应用服务中间件
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
|
3月前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
83 1
|
5月前
|
存储 数据库连接 数据库
如何使用Python上传文件到FTP服务器
如何使用Python上传文件到FTP服务器
75 1
|
5月前
|
JSON 编解码 Apache
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
57 1
|
Web App开发 JavaScript 前端开发
【转】 个人认为,这是最详细的 android------HttpURLConnection 类用法详解。一些教材没讲到的,它讲到了
站在巨人的肩膀上,渐渐进步。 原文链接:http://www.blogjava.net/supercrsky/articles/247449.html   针对JDK中的URLConnection连接Servlet的问题,网上有虽然有所涉及,但是只是说明了某一个或几个问题,是以FAQ的方式来解决的,而且比较零散,现在对这个类的使用就本人在项目中的使用经验做如下总结: 1:> URL请求的类别: 分为二类,GET与POST请求。
1287 0
|
1天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
3天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。