Java中用Socket實(shí)現(xiàn)HTTP文件上傳實(shí)例
我想做過(guò)web開(kāi)發(fā)的程序員大部分都做過(guò)文件上傳的功能,大多數(shù)時(shí)候我們都是借助于commons-fileupload這樣的jar包實(shí)現(xiàn)的。下面我試著通過(guò)讀取Socket的輸入流來(lái)實(shí)現(xiàn)一個(gè)文件上傳的功能。
在做文件上傳之前我們需要先了解一下HTTP POST的附件上傳協(xié)議。HTTP附件上傳協(xié)議是RFC1876協(xié)議,RFC1876協(xié)議是在HTTP協(xié)議的基礎(chǔ)上為INPUT標(biāo)簽增加了file屬性,同時(shí)限定了Form的method必須為POST,ENCTYPE必須為multipart/form-data。RFC1867協(xié)議對(duì)HTTP頭作了適當(dāng)?shù)刈兏?,content-type頭由以前的:content-type:application/x-www-form-urlencoded變?yōu)?code>content-type:multipart/form-data;+空格+boundary=字符串。RFC1867增加了文件上傳得功能,而上傳文件內(nèi)容自然也會(huì)被加入到HTTP的實(shí)體中?,F(xiàn)在因?yàn)榧扔蠬TTP一般的參數(shù)實(shí)體,又有上傳文件的實(shí)體,所以用boundary把每種實(shí)體進(jìn)行了分割。具體的看下圖:

接下來(lái)就開(kāi)始我們的代碼部分吧。
我在前面的文章中寫(xiě)過(guò)創(chuàng)建一個(gè)自己的Web服務(wù)器,現(xiàn)在我們的重點(diǎn)要放在對(duì)socket的輸入流的解析中。具體代碼如下:
public void parseRequest() {
LineNumberReader br = new LineNumberReader(new InputStreamReader(inputStream));
StringBuffer sb = new StringBuffer();
String str = null;
try {
//讀取請(qǐng)求行
String requestLine = br.readLine();
if (!StringUtils.isEmpty(requestLine)) {
sb.append(requestLine);
String[] reqs = requestLine.split(" ");
if (reqs != null && reqs.length > 0) {
if ("GET".equals(reqs[0])) {
method = "GET";
} else {
method = "POST";
}
}
}
//讀取請(qǐng)求頭
while ((str = br.readLine()) != null) {
if ("".equals(str)) {
break;
}
if (!StringUtils.isEmpty(str)) {
if (str.indexOf(":") > 0) {
String[] strs = str.split(":");
headers.put(strs[0].toLowerCase(), strs[1].trim());
}
}
sb.append(str).append("\n");
}
//POST請(qǐng)求,Content-type為 multipart/form-data
String contentType = null;
if ("POST".equals(method) && ((contentType = headers.get("content-type")) != null
&& headers.get("content-type").startsWith("multipart/form-data"))) {
//文件上傳的分割位 這里只處理單個(gè)文件的上傳
String boundary = contentType.substring(contentType.indexOf("boundary") +
"boundary=".length());
//解析消息體
while ((str = br.readLine()) != null) {
//解析結(jié)束的標(biāo)記
do {
//讀取boundary中的內(nèi)容
//讀取Content-Disposition
str = br.readLine();
//說(shuō)明是文件上傳
if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {
str = str.substring("Content-Disposition:".length());
String[] strs = str.split(";");
String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];
System.out.println("fileName = " + fileName);
//這一行是Content-Type
br.readLine();
//這一行是換行
br.readLine();
//正式去讀文件的內(nèi)容
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(new
FileOutputStream("G:\\LearnVideo\\fileLoad" +
File.separator + fileName), "UTF-8"));
while (true) {
str = br.readLine();
if (str.startsWith("--" + boundary)) {
break;
}
bw.write(str);
bw.newLine();
}
bw.flush();
} catch (Exception e) {
} finally {
if (bw != null) {
bw.close();
}
}
}
if (str.indexOf("Content-Disposition:") >= 0) {
str = str.substring("Content-Disposition:".length());
String[] strs = str.split(";");
String name = strs[strs.length - 1].replace("\"", "").split("=")[1];
br.readLine();
StringBuilder stringBuilder = new StringBuilder();
while (true) {
str = br.readLine();
if (str.startsWith("--" + boundary)) {
break;
}
stringBuilder.append(str);
}
parameters.put(name, stringBuilder.toString());
}
} while (("--" + boundary).equals(str));
//解析結(jié)束
if (str.equals("--" + boundary + "--")) {
break;
}
}
}
//System.out.println(sb.toString());
//獲取URI
uri = StringUtils.parserUri(sb.toString(), " ");
int flag = -1;
//說(shuō)明有參數(shù)
if ((flag = uri.indexOf('?')) >= 0) {
String oldUri = uri;
uri = uri.substring(0,flag);
String parameterPath = oldUri.substring(flag+1);
String[] parameter = parameterPath.split("&");
if (parameter != null && parameter.length > 0) {
for (int i = 0; i < parameter.length; i++) {
String str1 = parameter[i];
if((flag = str1.indexOf('=')) >= 0){
String key = str1.substring(0,flag);
String value = str1.substring(flag+1);
parameters.put(key,value);
}else{
parameters.put(str,null);
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
我們啟動(dòng)自己創(chuàng)建的Web服務(wù)器,然后在瀏覽器中輸入:http://localhost:8004/static/uploadPage.html,頁(yè)面如下:

選擇我們要上次的文件,然后點(diǎn)擊上傳按鈕,我們會(huì)發(fā)現(xiàn)我們的功能已經(jīng)被上傳到G:\LearnVideo\fileLoad這個(gè)目錄下了。示例如下:

完整的代碼請(qǐng)從這里下載:FullStackTraining_jb51.rar
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java 基于TCP Socket 實(shí)現(xiàn)文件上傳
- Socket+JDBC+IO實(shí)現(xiàn)Java文件上傳下載器DEMO詳解
- Java Socket+mysql實(shí)現(xiàn)簡(jiǎn)易文件上傳器的代碼
- JavaWeb實(shí)現(xiàn)文件上傳下載功能實(shí)例解析
- JAVA中使用FTPClient實(shí)現(xiàn)文件上傳下載實(shí)例代碼
- java實(shí)現(xiàn)FTP文件上傳與文件下載
- JavaWeb實(shí)現(xiàn)文件上傳下載功能實(shí)例詳解
- java web圖片上傳和文件上傳實(shí)例
- Java實(shí)現(xiàn)文件上傳至服務(wù)器的方法
- java使用Socket實(shí)現(xiàn)文件上傳功能
相關(guān)文章
java實(shí)現(xiàn)將字符串中首字母轉(zhuǎn)換成大寫(xiě),其它全部轉(zhuǎn)換成小寫(xiě)的方法示例
這篇文章主要介紹了java實(shí)現(xiàn)將字符串中首字母轉(zhuǎn)換成大寫(xiě),其它全部轉(zhuǎn)換成小寫(xiě)的方法,涉及java字符串遍歷、轉(zhuǎn)換、拼接等相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
23種設(shè)計(jì)模式(19)java責(zé)任鏈模式
這篇文章主要為大家詳細(xì)介紹了23種設(shè)計(jì)模式之java責(zé)任鏈模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
詳解Spring 中如何控制2個(gè)bean中的初始化順序
本篇文章主要介紹了Spring 中如何控制2個(gè)bean中的初始化順序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
SpringBoot中Shiro緩存使用Redis、Ehcache的方法
這篇文章主要介紹了SpringBoot中Shiro緩存使用Redis、Ehcache的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
spring boot 不連接數(shù)據(jù)庫(kù)啟動(dòng)的解決
這篇文章主要介紹了spring boot 不連接數(shù)據(jù)庫(kù)啟動(dòng)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
Java 常見(jiàn)的限流算法詳細(xì)分析并實(shí)現(xiàn)
大數(shù)據(jù)量高并發(fā)訪問(wèn)時(shí),經(jīng)常出現(xiàn)服務(wù)或接口面對(duì)暴漲的請(qǐng)求而不可用的情況,甚至引發(fā)連鎖反映導(dǎo)致整個(gè)系統(tǒng)崩潰。此時(shí)你需要使用的技術(shù)手段之一就是限流,當(dāng)請(qǐng)求達(dá)到一定的并發(fā)數(shù)或速率,就進(jìn)行等待、排隊(duì)、降級(jí)、拒絕服務(wù)等。限流時(shí),常見(jiàn)算法是計(jì)數(shù)器、漏斗、令牌桶算法2022-04-04
深入了解Spring中最常用的11個(gè)擴(kuò)展點(diǎn)
我們一說(shuō)到spring,可能第一個(gè)想到的是?IOC(控制反轉(zhuǎn))?和?AOP(面向切面編程)。除此之外,我們?cè)谑褂胹pring的過(guò)程中,有沒(méi)有發(fā)現(xiàn)它的擴(kuò)展能力非常強(qiáng)。今天就來(lái)跟大家一起聊聊,在Spring中最常用的11個(gè)擴(kuò)展點(diǎn)2022-09-09
spring?controller層引用service報(bào)空指針異常nullpointExceptio問(wèn)題
這篇文章主要介紹了spring?controller層引用service報(bào)空指針異常nullpointExceptio問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

