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

简介: Android端通过HttpURLConnection上传文件到服务器一:实现原理最近在做Android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做Spring3 MVC HTTP API作为后台上传接口,android客户端我选择用HttpURLConnection来通...

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


目录
相关文章
|
3月前
|
Android开发 数据安全/隐私保护 虚拟化
安卓手机远程连接登录Windows服务器教程
安卓手机远程连接登录Windows服务器教程
541 4
|
4月前
SecureCRT 通过xftp命令行上传文件到服务器上
SecureCRT 通过xftp命令行上传文件到服务器上
177 1
|
4月前
|
Ubuntu Linux Android开发
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
本文介绍了如何在Android设备上安装Termux和AnLinux,并通过这些工具运行Ubuntu系统和桌面环境。
347 2
termux+anlinux+Rvnc viewer来使安卓手机(平板)变成linux服务器
|
6月前
|
Java
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
Java使用FileInputStream&&FileOutputStream模拟客户端向服务器端上传文件(单线程)
110 1
|
8月前
|
存储 数据库连接 数据库
如何使用Python上传文件到FTP服务器
如何使用Python上传文件到FTP服务器
135 1
|
8月前
|
前端开发 Java API
Android端通过HttpURLConnection上传文件到服务器
Android端通过HttpURLConnection上传文件到服务器
120 0
|
9月前
|
监控 Unix 应用服务中间件
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
Android-音视频学习系列-(八)基于-Nginx-搭建(rtmp、http)直播服务器
|
3天前
|
机器学习/深度学习 人工智能 程序员
阿里云出手DeepSeek拒绝服务器繁忙,程序员直呼:真香!
阿里云PAI平台支持一键部署DeepSeek-V3和DeepSeek-R1大模型,用户无需编写代码即可完成从训练到部署的全过程。通过PAI Model Gallery,开发者可轻松选择并部署所需模型版本,享受高效、便捷的AI开发体验。教程详细介绍了开通PAI、选择模型及一键部署的具体步骤,帮助用户快速上手。
|
4天前
|
机器学习/深度学习 存储 弹性计算
阿里云gpu云服务器租用价格:最新收费标准及活动价格参考
阿里云gpu云服务器多少钱?A10卡GN7i GPU云服务器32核188G3213.99/1个月起,V100卡GN6v GPU云服务器8核32G3830.00/1个月起,阿里云GPU云服务器是基于GPU应用的计算服务,多适用于视频解码,图形渲染,深度学习,科学计算等应用场景,该产品具有超强计算能力、网络性能出色、购买方式灵活、高性能实例存储( GA1和GN5特有)等特点。下面小编来介绍下阿里云gpu云服务器最新的收费标准及活动价格。
|
4天前
|
存储 机器学习/深度学习 人工智能
2025年阿里云GPU服务器租用价格、选型策略与应用场景详解
随着AI与高性能计算需求的增长,阿里云提供了多种GPU实例,如NVIDIA V100、A10、T4等,适配不同场景。2025年重点实例中,V100实例GN6v单月3830元起,适合大规模训练;A10实例GN7i单月3213.99元起,适用于混合负载。计费模式有按量付费和包年包月,后者成本更低。针对AI训练、图形渲染及轻量级推理等场景,推荐不同配置以优化成本和性能。阿里云还提供抢占式实例、ESSD云盘等资源优化策略,支持eRDMA网络加速和倚天ARM架构,助力企业在2025年实现智能计算的效率与成本最优平衡。 (该简介为原文内容的高度概括,符合要求的字符限制。)

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    Android历史版本与APK文件结构
  • 3
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 10
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡