1 HTTP
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。
虽然在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。HttpClient 用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
一般的情况下我们都是使用Chrome或者其他浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据、文件上传下载等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。但是一旦我们有需求不通过浏览器来访问服务器的资源呢?那该怎么办呢?
下面以本地客户端发起文件的上传、下载为例做个小Demo。HttpClient有两种形式,一种是org.apache.http下的,一种是org.apache.commons.httpclient.HttpClient。
2 文件上传
文件上传可以使用两种方式实现,一种是PostMethod方式,一种是HttpPost方式。两者的处理大同小异。PostMethod是使用FileBody将文件包装流包装起来,HttpPost是使用FilePart将文件流包装起来。在传递文件流给服务端的时候,都可以同时传递其他的参数。
2.1 客户端处理
2.1.1 PostMethod方式
将文件封装到FilePart中,放入Part数组,同时,其他参数可以放入StringPart中,这里没有写,只是单纯的将参数以setParameter的方式进行设置。此处的HttpClient是org.apache.commons.httpclient.HttpClient。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
void
upload(String localFile){
File file =
new
File(localFile);
PostMethod filePost =
new
PostMethod(URL_STR);
HttpClient client =
new
HttpClient();
try
{
// 通过以下方法可以模拟页面参数提交
filePost.setParameter(
"userName"
, userName);
filePost.setParameter(
"passwd"
, passwd);
Part[] parts = {
new
FilePart(file.getName(), file) };
filePost.setRequestEntity(
new
MultipartRequestEntity(parts, filePost.getParams()));
client.getHttpConnectionManager().getParams().setConnectionTimeout(
5000
);
int
status = client.executeMethod(filePost);
if
(status == HttpStatus.SC_OK) {
System.out.println(
"上传成功"
);
}
else
{
System.out.println(
"上传失败"
);
}
}
catch
(Exception ex) {
ex.printStackTrace();
}
finally
{
filePost.releaseConnection();
}
}
|
记得搞完之后,要通过releaseConnection释放连接。
2.1.2 HttpPost方式
这种方式,与上面类似,只不过变成了FileBody。上面的Part数组在这里对应HttpEntity。此处的HttpClient是org.apache.http.client.methods下的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public
void
upload(String localFile){
CloseableHttpClient httpClient =
null
;
CloseableHttpResponse response =
null
;
try
{
httpClient = HttpClients.createDefault();
// 把一个普通参数和文件上传给下面这个地址 是一个servlet
HttpPost httpPost =
new
HttpPost(URL_STR);
// 把文件转换成流对象FileBody
FileBody bin =
new
FileBody(
new
File(localFile));
StringBody userName =
new
StringBody(
"Scott"
, ContentType.create(
"text/plain"
, Consts.UTF_8));
StringBody password =
new
StringBody(
"123456"
, ContentType.create(
"text/plain"
, Consts.UTF_8));
HttpEntity reqEntity = MultipartEntityBuilder.create()
// 相当于<input type="file" name="file"/>
.addPart(
"file"
, bin)
// 相当于<input type="text" name="userName" value=userName>
.addPart(
"userName"
, userName)
.addPart(
"pass"
, password)
.build();
httpPost.setEntity(reqEntity);
// 发起请求 并返回请求的响应
response = httpClient.execute(httpPost);
System.out.println(
"The response value of token:"
+ response.getFirstHeader(
"token"
));
// 获取响应对象
HttpEntity resEntity = response.getEntity();
if
(resEntity !=
null
) {
// 打印响应长度
System.out.println(
"Response content length: "
+ resEntity.getContentLength());
// 打印响应内容
System.out.println(EntityUtils.toString(resEntity, Charset.forName(
"UTF-8"
)));
}
// 销毁
EntityUtils.consume(resEntity);
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
try
{
if
(response !=
null
){
response.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
try
{
if
(httpClient !=
null
){
httpClient.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
|
2.2 服务端处理
无论客户端是哪种上传方式,服务端的处理都是一样的。在通过HttpServletRequest获得参数之后,把得到的Item进行分类,分为普通的表单和File表单。
通过ServletFileUpload 可以设置上传文件的大小及编码格式等。
总之,服务端的处理是把得到的参数当做HTML表单进行处理的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
public
void
processUpload(HttpServletRequest request, HttpServletResponse response){
File uploadFile =
new
File(uploadPath);
if
(!uploadFile.exists()) {
uploadFile.mkdirs();
}
System.out.println(
"Come on, baby ......."
);
request.setCharacterEncoding(
"utf-8"
);
response.setCharacterEncoding(
"utf-8"
);
//检测是不是存在上传文件
boolean
isMultipart = ServletFileUpload.isMultipartContent(request);
if
(isMultipart){
DiskFileItemFactory factory =
new
DiskFileItemFactory();
//指定在内存中缓存数据大小,单位为byte,这里设为1Mb
factory.setSizeThreshold(
1024
*
1024
);
//设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录
factory.setRepository(
new
File(
"D:\\temp"
));
// Create a new file upload handler
ServletFileUpload upload =
new
ServletFileUpload(factory);
// 指定单个上传文件的最大尺寸,单位:字节,这里设为50Mb
upload.setFileSizeMax(
50
*
1024
*
1024
);
//指定一次上传多个文件的总尺寸,单位:字节,这里设为50Mb
upload.setSizeMax(
50
*
1024
*
1024
);
upload.setHeaderEncoding(
"UTF-8"
);
List<FileItem> items =
null
;
try
{
// 解析request请求
items = upload.parseRequest(request);
}
catch
(FileUploadException e) {
e.printStackTrace();
}
if
(items!=
null
){
//解析表单项目
Iterator<FileItem> iter = items.iterator();
while
(iter.hasNext()) {
FileItem item = iter.next();
//如果是普通表单属性
if
(item.isFormField()) {
//相当于input的name属性 <input type="text" name="content">
String name = item.getFieldName();
//input的value属性
String value = item.getString();
System.out.println(
"属性:"
+ name +
" 属性值:"
+ value);
}
//如果是上传文件
else
{
//属性名
String fieldName = item.getFieldName();
//上传文件路径
String fileName = item.getName();
fileName = fileName.substring(fileName.lastIndexOf(
"/"
) +
1
);
// 获得上传文件的文件名
try
{
item.write(
new
File(uploadPath, fileName));
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
}
response.addHeader(
"token"
,
"hello"
);
}
|
服务端在处理之后,可以在Header中设置返回给客户端的简单信息。如果返回客户端是一个流的话,流的大小必须提前设置!
response.setContentLength((int) file.length());
3 文件下载
文件的下载可以使用HttpClient的GetMethod实现,还可以使用HttpGet方式、原始的HttpURLConnection方式。
3.1 客户端处理
3.1.1 GetMethod方式
此处的HttpClient是org.apache.commons.httpclient.HttpClient。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
void
downLoad(String remoteFileName, String localFileName) {
HttpClient client =
new
HttpClient();
GetMethod get =
null
;
FileOutputStream output =
null
;
try
{
get =
new
GetMethod(URL_STR);
get.setRequestHeader(
"userName"
, userName);
get.setRequestHeader(
"passwd"
, passwd);
get.setRequestHeader(
"fileName"
, remoteFileName);
int
i = client.executeMethod(get);
if
(SUCCESS == i) {
System.out.println(
"The response value of token:"
+ get.getResponseHeader(
"token"
));
File storeFile =
new
File(localFileName);
output =
new
FileOutputStream(storeFile);
// 得到网络资源的字节数组,并写入文件
output.write(get.getResponseBody());
}
else
{
System.out.println(
"DownLoad file occurs exception, the error code is :"
+ i);
}
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
try
{
if
(output !=
null
){
output.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
get.releaseConnection();
client.getHttpConnectionManager().closeIdleConnections(
0
);
}
}
|
3.1.2 HttpGet方式
此处的HttpClient是org.apache.http.client.methods下的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
public
void
downLoad(String remoteFileName, String localFileName) {
DefaultHttpClient httpClient =
new
DefaultHttpClient();
OutputStream out =
null
;
InputStream in =
null
;
try
{
HttpGet httpGet =
new
HttpGet(URL_STR);
httpGet.addHeader(
"userName"
, userName);
httpGet.addHeader(
"passwd"
, passwd);
httpGet.addHeader(
"fileName"
, remoteFileName);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity entity = httpResponse.getEntity();
in = entity.getContent();
long
length = entity.getContentLength();
if
(length <=
0
) {
System.out.println(
"下载文件不存在!"
);
return
;
}
System.out.println(
"The response value of token:"
+ httpResponse.getFirstHeader(
"token"
));
File file =
new
File(localFileName);
if
(!file.exists()){
file.createNewFile();
}
out =
new
FileOutputStream(file);
byte
[] buffer =
new
byte
[
4096
];
int
readLength =
0
;
while
((readLength=in.read(buffer)) >
0
) {
byte
[] bytes =
new
byte
[readLength];
System.arraycopy(buffer,
0
, bytes,
0
, readLength);
out.write(bytes);
}
out.flush();
}
catch
(IOException e) {
e.printStackTrace();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
try
{
if
(in !=
null
){
in.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
try
{
if
(out !=
null
){
out.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
|
3.1.3 HttpURLConnection方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
public
void
download3(String remoteFileName, String localFileName) {
FileOutputStream out =
null
;
InputStream in =
null
;
try
{
URL url =
new
URL(URL_STR);
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
// true -- will setting parameters
httpURLConnection.setDoOutput(
true
);
// true--will allow read in from
httpURLConnection.setDoInput(
true
);
// will not use caches
httpURLConnection.setUseCaches(
false
);
// setting serialized
httpURLConnection.setRequestProperty(
"Content-type"
,
"application/x-java-serialized-object"
);
// default is GET
httpURLConnection.setRequestMethod(
"POST"
);
httpURLConnection.setRequestProperty(
"connection"
,
"Keep-Alive"
);
httpURLConnection.setRequestProperty(
"Charsert"
,
"UTF-8"
);
// 1 min
httpURLConnection.setConnectTimeout(
60000
);
// 1 min
httpURLConnection.setReadTimeout(
60000
);
httpURLConnection.addRequestProperty(
"userName"
, userName);
httpURLConnection.addRequestProperty(
"passwd"
, passwd);
httpURLConnection.addRequestProperty(
"fileName"
, remoteFileName);
// connect to server (tcp)
httpURLConnection.connect();
in = httpURLConnection.getInputStream();
// send request to
// server
File file =
new
File(localFileName);
if
(!file.exists()){
file.createNewFile();
}
out =
new
FileOutputStream(file);
byte
[] buffer =
new
byte
[
4096
];
int
readLength =
0
;
while
((readLength=in.read(buffer)) >
0
) {
byte
[] bytes =
new
byte
[readLength];
System.arraycopy(buffer,
0
, bytes,
0
, readLength);
out.write(bytes);
}
out.flush();
}
catch
(Exception e){
e.printStackTrace();
}
finally
{
try
{
if
(in !=
null
){
in.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
try
{
if
(out !=
null
){
out.close();
}
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
|
3.2 服务端处理
尽管客户端的处理方式不同,但是服务端是一样的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public
void
processDownload(HttpServletRequest request, HttpServletResponse response){
int
BUFFER_SIZE =
4096
;
InputStream in =
null
;
OutputStream out =
null
;
System.out.println(
"Come on, baby ......."
);
try
{
request.setCharacterEncoding(
"utf-8"
);
response.setCharacterEncoding(
"utf-8"
);
response.setContentType(
"application/octet-stream"
);
String userName = request.getHeader(
"userName"
);
String passwd = request.getHeader(
"passwd"
);
String fileName = request.getHeader(
"fileName"
);
System.out.println(
"userName:"
+ userName);
System.out.println(
"passwd:"
+ passwd);
System.out.println(
"fileName:"
+ fileName);
//可以根据传递来的userName和passwd做进一步处理,比如验证请求是否合法等
File file =
new
File(downloadPath +
"\\"
+ fileName);
response.setContentLength((
int
) file.length());
response.setHeader(
"Accept-Ranges"
,
"bytes"
);
int
readLength =
0
;
in =
new
BufferedInputStream(
new
FileInputStream(file), BUFFER_SIZE);
out =
new
BufferedOutputStream(response.getOutputStream());
byte
[] buffer =
new
byte
[BUFFER_SIZE];
while
((readLength=in.read(buffer)) >
0
) {
byte
[] bytes =
new
byte
[readLength];
System.arraycopy(buffer,
0
, bytes,
0
, readLength);
out.write(bytes);
}
out.flush();
response.addHeader(
"token"
,
"hello 1"
);
}
catch
(Exception e){
e.printStackTrace();
response.addHeader(
"token"
,
"hello 2"
);
}
finally
{
if
(in !=
null
) {
try
{
in.close();
}
catch
(IOException e) {
}
}
if
(out !=
null
) {
try
{
out.close();
}
catch
(IOException e) {
}
}
}
}
|
4 小结
HttpClient最基本的功能就是执行Http方法。一个Http方法的执行涉及到一个或者多个Http请求/Http响应的交互,通常这个过程都会自动被HttpClient处理,对用户透明。用户只需要提供Http请求对象,HttpClient就会将http请求发送给目标服务器,并且接收服务器的响应,如果http请求执行不成功,httpclient就会抛出异常。所以在写代码的时候注意finally的处理。
所有的Http请求都有一个请求列(request line),包括方法名、请求的URI和Http版本号。HttpClient支持HTTP/1.1这个版本定义的所有Http方法:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。上面的上传用到了Post,下载是Get。
目前来说,使用org.apache.commons.httpclient.HttpClient多一些。看自己了~
以上就是小编为大家带来的使用HttpClient实现文件的上传下载方法全部内容了,希望大家多多支持脚本之家~