最近手邊的專案漸漸由 HttpClient 3.x 轉移至改用 HttpClient 4.x 實作 Http 操作。
使用 Commons 專案的東西,捨棄原始的 HttpURLConnection 就是為了較輕鬆地處理 Http 操作的功能。
我們可以用下列方式透過網頁表單上傳檔案:
HttpClient client = new DefaultHttpClient();
HttpPost post =new HttpPost("http://example.com/upload.do");
MultipartEntity e = new MultipartEntity();
try{
e.addPart("field1", new StringBody("some value"));
e.addPart("file", new FileBody(new File("your_file_path")));
}catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
post.setEntity(e);
client.execute(post);
它的寫法是相當容易的!不過有個小缺點,那就是 HttpClient 4.x 某個版本將 Multipart Entity 實作獨立至 HttpMime 專案
http://hc.apache.org/httpcomponents-client/httpmime/index.html
所以,您要使用單純的表單上傳功能,就需要同時再引用 HttpMime 相關的 Library
C:\http-mime>dir
磁碟區 C 中的磁碟沒有標籤。
磁碟區序號: A8B9-DC3D
C:\http-mime 的目錄
2010/01/01 下午 01:20 <DIR> .
2010/01/01 下午 01:20 <DIR> ..
2009/12/31 下午 02:22 345,048 apache-mime4j-0.6.jar
2009/12/31 下午 02:22 25,993 httpmime-4.0.jar
2009/12/31 下午 02:22 2,255 jcip-annotations-1.0.jar
3 個檔案 373,296 位元組
2 個目錄 70,042,320,896 位元組可用
雖然,這些 Library 僅 300 多 kb,對一般的應用程式開發來說並不算什麼。
但總覺得是否能讓它單純一些呢?我們並不需要完整而強大的 Http Mime,
有時我們只需要足夠的功能罷了!隨著這個想法,試著實作一個極簡版本的 ThinMultipartEntity。
可以不需引用 HttpMime 就上傳檔案。
package com.google.jplurk.net;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader;
public class ThinMultipartEntity implements HttpEntity {
static Log logger = LogFactory.getLog(ThinMultipartEntity.class);
private final static char[] MULTIPART_CHARS =
"-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray();
private String boundary = null;
ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean isSetLast = false;
boolean isSetFirst = false;
public ThinMultipartEntity() {
StringBuffer buf = new StringBuffer();
Random rand = new Random();
for (int i = 0; i < 30; i++) {
buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
}
this.boundary = buf.toString();
}
public void writeFirstBoundary(){
if(!isSetFirst){
try {
out.write(("--" + boundary + "\r\n").getBytes());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
isSetFirst = true;
}
public void writeLastBoundary() {
if(isSetLast){
return ;
}
try {
out.write(("\r\n--" + boundary + "--\r\n").getBytes());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
isSetLast = true;
}
public void addPart(String key, String value) {
writeFirstBoundary();
try {
out.write(("Content-Disposition: form-data; name=\"" +key+"\"\r\n").getBytes());
out.write("Content-Type: text/plain; charset=UTF-8\r\n".getBytes());
out.write("Content-Transfer-Encoding: 8bit\r\n\r\n".getBytes());
out.write(value.getBytes());
out.write(("\r\n--" + boundary + "\r\n").getBytes());
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public void addPart(String key, File value) {
writeFirstBoundary();
try {
out.write(("Content-Disposition: form-data; name=\""
+ key+"\"; filename=\"" + value.getName()+ "\"\r\n").getBytes());
out.write("Content-Type: application/octet-stream\r\n".getBytes());
out.write("Content-Transfer-Encoding: binary\r\n\r\n".getBytes());
FileInputStream fin = new FileInputStream(value);
int data = fin.read();
while(data !=-1){
out.write(data);
data = fin.read();
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public long getContentLength() {
writeLastBoundary();
return out.toByteArray().length;
}
public Header getContentType() {
return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
}
public boolean isChunked() {
return false;
}
public boolean isRepeatable() {
return false;
}
public boolean isStreaming() {
return false;
}
public void writeTo(OutputStream outstream) throws IOException {
outstream.write(out.toByteArray());
}
public Header getContentEncoding() {
return null;
}
public void consumeContent() throws IOException,
UnsupportedOperationException {
if (isStreaming()) {
throw new UnsupportedOperationException(
"Streaming entity does not implement #consumeContent()");
}
}
public InputStream getContent() throws IOException,
UnsupportedOperationException {
throw new UnsupportedOperationException(
"Multipart form entity does not implement #getContent()");
}
}
PS. 因為是極簡版的,有許多細節是被省略的
PS. 只試過上傳一個檔 XD
沒有留言:
張貼留言