`
newslxw
  • 浏览: 207785 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JAVA使用HttpUrlConnection实现自动上传文件

阅读更多

 

首先,实现自动上传文件方式有很多种,其中就有 SOCKET RMI HTTP 等,考虑到服务器本身是个网站服务器,使用 SOCKET RMI 需要单独开发端口, HTTP 则可以直接融合到网站中,也没有特殊的要求,所以采用了 HTTP 方式。 HTTP 方式又有好几种,其中就有 hessian HttpUrlConnection 。使用 hessian 的话, hessian 提供的流上传有缺陷,可能会导致内存溢出,因此只能是将文件以多个字节数组方式传输到服务器,然后程序再整合字节成完整文件,无疑增加了代码复杂度。所以最终选择了 HttpUrlConnection

 

通过 HttpUrlConnection 自动上传文件,服务端和用户通过网页上传文件到服务器的程序一模一样,只是客户端,我们用 HttpUrlConnection 来代替浏览器向服务器提交数据。因此我们首先要弄清楚浏览器发送数据的格式。

 

第1步,数据格式:

发送文件, method POST multipart/form-data ;我们通过 firefox firebug 查看具体上传

下面数据是 iteye 上上传一个空文件是的 firebug 提交的数据。

文件格式如下:

head

 

Content-Length 357
Content-Type 
multipart/form-data; boundary=---------------------------41184676334

 body

-----------------------------41184676334 
Content-Disposition: form-data; name="authenticity_token" 


vggMNy0klrhNiSh9bQkSYeN/c3tx11I/lS0T7YDpc9U= 
-----------------------------41184676334 
Content-Disposition: form-data; name="attachment[uploaded_data]"; filename="test.zip" Content-Type: application/zip


 -----------------------------41184676334—

 

 

格式解析:

 

Content-Length 定义了发送数据的总字节数;

Content-Type 定义格式和数据分界符 boundary ,下面发送的数据将用这个 boundary 分隔每一个变量, boundary 中的 41184676334 是由浏览器随机生成,我们可以直接使用

发送 2 个变量,分别是 authenticity_token 和空文件 test.zip

变量开头是 “--”+boundary ,然后下一行 Content-Disposition 定义变量名称,下一行是 content-type 定义数据格式,这个不是必须的,发送文件数据时, content-type 需要指定,

这里指出了文件类型,我们可以用 application/octet-stream 告诉服务器发送的是流,再空两行(即 \r\n\r\n ),是变量的值或者文件的内容。然后下一行开始是另外一个变量。最后一个变量以 “—“+boundary+”—“ 结束。

 

第2步 HTTPS 处理

有时候网站采用的是 HTTPS 协议,因此我们需要相应的证书,我们考虑是让程序接受所有证书,就像浏览器上设置接受所有证书,不管签名与否。实际是我们也无需证书,服务器也是我们自己的,我当然相信自己编写的客户端当然也相信自己的服务端了。

 

 

要接受所有服务器上的证书,我们需要实现两个接口

javax.net.ssl.X509TrustManager javax.net.ssl.HostnameVerifier

接口中的函数都以空函数覆盖即可。其中 javax.net.ssl.HostnameVerifier verify 返回 true 即可。下面是我们连接服务器的函数

 

 

HttpURLConnection getHttpConnection(String urlString) throws Exception
	{
		URL url = new URL(urlString);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		if ("https".equalsIgnoreCase(url.getProtocol()))    
        {
            HttpsURLConnection httpsConn=(HttpsURLConnection) conn;
            TrustManager[] managers ={new MyX509TrustManager()};
            SSLContext sslContext=SSLContext.getInstance("TLS");
            sslContext.init(null, managers, new SecureRandom());
            SSLSocketFactory ssf=sslContext.getSocketFactory();
            httpsConn.setSSLSocketFactory(ssf);
            httpsConn.setHostnameVerifier(new MyHostnameVerifier());
            return httpsConn;
        }
		else
		{
			return conn;
		}
	}

 

其中 MyX509TrustManager MyHostnameVerifier 分别是

javax.net.ssl.X509TrustManager javax.net.ssl.HostnameVerifier 的实现类。

 

 

3 步,发送数据

连接了服务器,就可以发送数据了。

首先定义连接的 header 和连接方式和 boundary

conn = getHttpConnection(urlString);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
String BOUNDARY = "---------------------------41184676334";

conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Charsert", "UTF-8");
conn.setRequestProperty("user-agent",
					"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0");						//可以不指定
conn.setRequestProperty("Content-Type",
					"multipart/form-data; boundary=" + BOUNDARY);
conn.setRequestProperty("Content-Length",
					String.valueOf(contentLen));  //不清楚长度,可以不写
			
conn.setAllowUserInteraction(false);    //无需用户交互,即弹出https等的对话框。
conn.setChunkedStreamingMode(blockSize);   //告诉HttpUrlConnection,我们需要采用流方式上传数据,无需本地缓存数据。HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。

byte[] end_data = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
StringBuffer sb = new StringBuffer();

sb.append("--").append(BOUNDARY).append("\r\n");
sb.append("Content-Disposition: form-data; name=\"username\"\r\n\r\n");
sb.append(username);
sb.append("\r\n--").append(BOUNDARY).append("\r\n");

sb.append("--").append(BOUNDARY).append("\r\n");
sb.append("Content-Disposition: form-data; name=\"password\"\r\n\r\n");
sb.append(password);
sb.append("\r\n--").append(BOUNDARY).append("\r\n");

sb.append("--").append(BOUNDARY).append("\r\n");
sb.append("Content-Disposition: form-data; name=\"file\"; filename=\identify.zip\"\r\n");
sb.append("Content-Type: application/octet-stream\r\n\r\n");

byte[] data = sb.toString().getBytes();
long fLen = f.length();
long contentLen = data.length + fLen + end_data.length;
os.write(data);  //发送非文件数据
			
fis = new FileInputStream(f);  //读取文件内容,发送数据,数据要一点点发送,不能一下全部读取发送,否则会内存溢出。
int rn;
byte[] buf = new byte[blockSize];  
while ((rn = fis.read(buf, 0, blockSize)) > 0) {
	os.write(buf, 0, rn);
}
os.write(end_data);
os.flush();
os.close();
fis.close();

  4 步,接受服务器处理结果

ByteArrayOutputStream bo = new ByteArrayOutputStream();
InputStream is = conn.getInputStream();
byte[] inbuf = new byte[blockSize/10];
while ((rn = is.read(inbuf, 0, blockSize/10)) > 0) {
				bo.write(inbuf);
}
is.close();
String ret = bo.toString();
bo.close();

 

 

分享到:
评论

相关推荐

    对Java的HttpURLConnection的封装类

    用于模拟浏览器访问网页,抓取站点源文件。...  * version 1.0.0_00,支持POST数据,支持SSL,支持上传文件。  * GET、POST方式无需设置自动判断。  * 代码经过优化和修理。  【API简介】  

    Google Android SDK开发范例大全(PDF高清完整版3)(4-3)

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK开发范例大全(PDF完整版4)(4-4)

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK开发范例大全(PDF高清完整版1)(4-1)

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK开发范例大全(完整版附部分源码).pdf

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片...

    Google Android SDK开发范例大全的目录

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google+Android+SDK开发范例大全

    4.10 心爱小宝贝相片集——Gallery与衍生BaseAdapter容器 4.11 快速的搜索手机文件引擎——JavaI/O的应用 4.12 按钮也能随点击变换——ImageButton选择特效 4.13 具自动提示功能的菜单——AutoCompleteTextView与...

    Google Android sdk 开发范例大全 部分章节代码

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK 开发范例大全01

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK 开发范例大全02

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Google Android SDK开发范例大全(完整版)

    4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——...

    Android典型技术模块开发详解

    11.3.4 文件上传 11.4 HttpClient 11.4.1 HttpGet请求 11.4.2 HttpPost请求 11.5 本章小结 第12章 数据解析 12.1 XML 12.1.1 DOM 12.1.2 SAX 12.1.3 PULL 12.2 JSON格式 12.2.1 基本类型 12.2.2 数组和集合 12.2.3 ...

Global site tag (gtag.js) - Google Analytics