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

50 篇文章 0 订阅

http://www.iteye.com/topic/1123667


首先,实现自动上传文件方式有很多种,其中就有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

-----------------------------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.X509TrustManagerjavax.net.ssl.HostnameVerifier

接口中的函数都以空函数覆盖即可。其中javax.net.ssl.HostnameVerifierverify返回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();





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用JavaHttpURLConnection实现上传多个文件,你可以按以下步骤进行操作: 1. 导入必要的类: ```java import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; ``` 2. 创建一个方法来处理文件上传: ```java public void uploadFiles(String url, String[] filePaths) throws IOException { String boundary = "===" + System.currentTimeMillis() + "==="; String lineBreak = "\r\n"; URL uploadUrl = new URL(url); HttpURLConnection connection = (HttpURLConnection) uploadUrl.openConnection(); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); OutputStream outputStream = connection.getOutputStream(); for (String filePath : filePaths) { File file = new File(filePath); FileInputStream fileInputStream = new FileInputStream(file); // 写入文件开始分隔符 outputStream.write((lineBreak + "--" + boundary + lineBreak).getBytes()); // 写入Content-Disposition头部信息 outputStream.write(("Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + lineBreak).getBytes()); outputStream.write(("Content-Type: application/octet-stream" + lineBreak).getBytes()); // 写入空行 outputStream.write(lineBreak.getBytes()); // 写入文件内容 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fileInputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } fileInputStream.close(); } // 写入结束分隔符 outputStream.write((lineBreak + "--" + boundary + "--" + lineBreak).getBytes()); outputStream.flush(); outputStream.close(); // 获取响应 int responseCode = connection.getResponseCode(); // 根据需要进行处理响应结果 connection.disconnect(); } ``` 3. 调用`uploadFiles`方法,传入要上传的文件路径和目标URL: ```java String url = "http://example.com/upload"; String[] filePaths = {"/path/to/file1", "/path/to/file2"}; uploadFiles(url, filePaths); ``` 在这个示例中,我们首先创建了一个URL对象,并打开了一个HttpURLConnection。然后,我们设置了请求方法为POST,并设置了Content-Type为multipart/form-data,这是用于上传文件的常用类型。 接下来,我们逐个处理每个文件。我们首先写入文件开始的分隔符,并设置文件的Content-Disposition头部信息。然后,我们写入文件的内容。最后,我们写入文件结束的分隔符。 在写入完所有文件后,我们将输出流刷新并关闭连接。然后,我们可以根据需要处理服务器的响应。 这是一个简单的示例,你可以根据需要进行修改和扩展。确保在实际应用中进行适当的异常处理和错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值