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";
}
} }
Android端通过HttpURLConnection上传文件到服务器的更多相关文章
- Android端通过HttpURLConnection上传文件到server
Android端通过HttpURLConnection上传文件到server 一:实现原理 近期在做Androidclient的应用开发,涉及到要把图片上传到后台server中.自己选择了做Sprin ...
- Android上传文件至服务器(上)
每一次都不能上首页,真悲催..管理员让我上一次首页? 很多时候我更愿意一个人写代码,与其在垃圾代码上改改改,我更愿意直接重构. 整洁的代码简单直接.整洁的代码如同优美的散文.整洁的代码从不隐藏设计者的 ...
- android上传文件到服务器
package com.spring.sky.image.upload.network; import java.io.DataOutputStream; import java.io.File; i ...
- android -上传文件到服务器
android上传文件到服务器 重点:最好是设置好content-type这些参数的配置! package com.spring.sky.image.upload.network; ...
- java http工具类和HttpUrlConnection上传文件分析
利用java中的HttpUrlConnection上传文件,我们其实只要知道Http协议上传文件的标准格式.那么就可以用任何一门语言来模拟浏览器上传文件.下面有几篇文章从http协议入手介绍了java ...
- HttpURLConnection上传文件
HttpURLConnection上传文件 import java.io.BufferedReader; import java.io.DataInputStream; import java.io. ...
- WPF上传文件到服务器
利用WebClient 上传文件到服务器 创建一个空网站,创建一个UploadFile.aspx项, 服务器报500错误:检查文件保存路径是否存在,检查文件大小限制 protected void Pa ...
- joomla安装插件报错:上传文件到服务器发生了一个错误。 过小的PHP文件上传尺寸
在安装joomla的AKeeba插件的时候报错如下:上传文件到服务器发生了一个错误. 过小的PHP文件上传尺寸.解决方法是修改php.ini文件,打开文件后搜索upload_max_filesize! ...
- 用winscp从本地上传文件到服务器上出现复制文件到远端时错误。
用winscp从本地上传文件到服务器上出现复制文件到远端时错误. 错误码:4 服务器返回的错误消息:write failed 报错如下图所示: 分析过程: 1.刚开始以为是权限不够,后面上网查了一下是 ...
随机推荐
- bzoj 2956 数学展开,分段处理
首先对于答案 ΣΣ(n mod i)*(m mod j) i<>j 也就是Σ(n mod i)Σ(m mod j)-Σ(n mod i)(m mod i) 将mod展开,我们可以得到有fl ...
- VIM 技巧 (一)全文统一添加
大家应该有遇到过给整篇内容增加同样的东西的经历.例如给每行结尾增加分号.冒号等内容. 今天和大家分享下 关于此场景如何快速.高效的实现. 例如 Line one Line two Line three ...
- WPF 验证
WPF中TextBox的自动验证: 演示 : 用以下两个TextBox分别显示验证IP和非空值验证,先看效果: IP自动验证效果: 非空值自动验证效果: 第一步:定义TextBox验证的样式: < ...
- poj 2187
求凸包后枚举凸包上的点 #include <cstdio> #include <cstdlib> #include <cmath> #include <map ...
- hadoop-ha QJM架构应用故障总结
部署hadoop-ha QJM架构过程我就不说了,参考 我的博客:hadoop-ha QJM架构部署故障一: namenode 报错日志如下: WARN org.apache.hadoop.hd ...
- 停止使用循环 教你用underscore优雅的写代码
你一天(一周)内写了多少个循环了? var i; for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; ...
- Sqli-labs less 52
Less-52 和less50是一样的,只是这里的mysql错误不会在前台显示,但是对于stacked injection是一样的利用方式 http://127.0.0.1/sqli-labs/Les ...
- 本地安装xssing
本地安装xssing 环境为apache+mysql+php,linux下和Windows均进行了尝试. 步骤: (1)Mysql中创建xing数据库,将xssing.sql中的语句复制并在xing数 ...
- vim使用指北 ---- Global Replacement
一般替换 s/old/new --- 替换当前行的第一个匹配项 s/old/new/g ---- 替换当前行所有的匹配项 number1,number2-s/old/new/g ---- 替换从 ...
- 同一网站不同和二级域名和不同子目录的cookie
1.cookie二级域名的实现: 用户其中一个站点登录,而且可以各个子频道间切换,保持登录状态设置Cookie时,使用如下代码即可:setcookie(name,value,expire,path,& ...