使用HttpClient實現(xiàn)文件的上傳下載方法
1 HTTP
HTTP 協(xié)議可能是現(xiàn)在 Internet 上使用得最多、最重要的協(xié)議了,越來越多的 Java 應用程序需要直接通過 HTTP 協(xié)議來訪問網(wǎng)絡資源。
雖然在 JDK 的 java.net 包中已經(jīng)提供了訪問 HTTP 協(xié)議的基本功能,但是對于大部分應用程序來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。
一般的情況下我們都是使用Chrome或者其他瀏覽器來訪問一個WEB服務器,用來瀏覽頁面查看信息或者提交一些數(shù)據(jù)、文件上傳下載等等。所訪問的這些頁面有的僅僅是一些普通的頁面,有的需要用戶登錄后方可使用,或者需要認證以及是一些通過加密方式傳輸,例如HTTPS。目前我們使用的瀏覽器處理這些情況都不會構成問題。但是一旦我們有需求不通過瀏覽器來訪問服務器的資源呢?那該怎么辦呢?
下面以本地客戶端發(fā)起文件的上傳、下載為例做個小Demo。HttpClient有兩種形式,一種是org.apache.http下的,一種是org.apache.commons.httpclient.HttpClient。
2 文件上傳
文件上傳可以使用兩種方式實現(xiàn),一種是PostMethod方式,一種是HttpPost方式。兩者的處理大同小異。PostMethod是使用FileBody將文件包裝流包裝起來,HttpPost是使用FilePart將文件流包裝起來。在傳遞文件流給服務端的時候,都可以同時傳遞其他的參數(shù)。
2.1 客戶端處理
2.1.1 PostMethod方式
將文件封裝到FilePart中,放入Part數(shù)組,同時,其他參數(shù)可以放入StringPart中,這里沒有寫,只是單純的將參數(shù)以setParameter的方式進行設置。此處的HttpClient是org.apache.commons.httpclient.HttpClient。
public void upload(String localFile){
File file = new File(localFile);
PostMethod filePost = new PostMethod(URL_STR);
HttpClient client = new HttpClient();
try {
// 通過以下方法可以模擬頁面參數(shù)提交
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數(shù)組在這里對應HttpEntity。此處的HttpClient是org.apache.http.client.methods下的。
public void upload(String localFile){
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClients.createDefault();
// 把一個普通參數(shù)和文件上傳給下面這個地址 是一個servlet
HttpPost httpPost = new HttpPost(URL_STR);
// 把文件轉(zhuǎn)換成流對象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);
// 發(fā)起請求 并返回請求的響應
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());
// 打印響應內(nèi)容
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獲得參數(shù)之后,把得到的Item進行分類,分為普通的表單和File表單。
通過ServletFileUpload 可以設置上傳文件的大小及編碼格式等。
總之,服務端的處理是把得到的參數(shù)當做HTML表單進行處理的。
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();
//指定在內(nèi)存中緩存數(shù)據(jù)大小,單位為byte,這里設為1Mb
factory.setSizeThreshold(1024*1024);
//設置一旦文件大小超過getSizeThreshold()的值時數(shù)據(jù)存放在硬盤的目錄
factory.setRepository(new File("D:\\temp"));
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// 指定單個上傳文件的最大尺寸,單位:字節(jié),這里設為50Mb
upload.setFileSizeMax(50 * 1024 * 1024);
//指定一次上傳多個文件的總尺寸,單位:字節(jié),這里設為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實現(xiàn),還可以使用HttpGet方式、原始的HttpURLConnection方式。
3.1 客戶端處理
3.1.1 GetMethod方式
此處的HttpClient是org.apache.commons.httpclient.HttpClient。
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);
// 得到網(wǎng)絡資源的字節(jié)數(shù)組,并寫入文件
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下的。
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方式
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 服務端處理
盡管客戶端的處理方式不同,但是服務端是一樣的。
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);
//可以根據(jù)傳遞來的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最基本的功能就是執(zhí)行Http方法。一個Http方法的執(zhí)行涉及到一個或者多個Http請求/Http響應的交互,通常這個過程都會自動被HttpClient處理,對用戶透明。用戶只需要提供Http請求對象,HttpClient就會將http請求發(fā)送給目標服務器,并且接收服務器的響應,如果http請求執(zhí)行不成功,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多一些??醋约毫藒
以上就是小編為大家?guī)淼氖褂肏ttpClient實現(xiàn)文件的上傳下載方法全部內(nèi)容了,希望大家多多支持腳本之家~
相關文章
Java異常處理之java.lang.ClassCastException問題
這篇文章主要介紹了Java異常處理之java.lang.ClassCastException問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
基于logback 實現(xiàn)springboot超級詳細的日志配置
java web 下有好幾種日志框架,比如:logback,log4j,log4j2(slj4f 并不是一種日志框架,它相當于定義了規(guī)范,實現(xiàn)了這個規(guī)范的日志框架就能夠用 slj4f 調(diào)用)。這篇文章主要介紹了基于logback springboot超級詳細的日志配置,需要的朋友可以參考下2019-06-06

